Jump to content

Aperture - AI-Powered Recommendations for Emby


Recommended Posts

akacharos
Posted

Well, then I'll start providing some feedback from my usage!
One thing that I see as a privacy concern is that the API endpoints are exposed without a required auth token. I believe API endpoints should be restricted without some authentication.

akacharos
Posted

Wait, I'm wrong. It looks like I hit a "error    "Unauthorized" now.
Interesting. So API access is based on browser session?

Jdiesel
Posted
2 hours ago, TheGru said:

I would love to see it happen, and would be more than happy to adapt Aperture to that. I don't think it would be much effort at all, as along as playlists can be associated on a per user basis!

I know this had been shelved for now but I couldn't help but think of this potential workaround. I might be missing something obvious but here goes...

What if all libraries, including the main Movie and TV libraries, were virtual libraries created by Aperture (.strm or symlinks libraries)? This way Aperture could have full control over the contents of each library.

Conventional or real libraries are created in Emby and function as expected (scrape metadata, playback history, etc.). Ideally these library would only be accessible to the admin user and not other users, but I don't believe that is possible.

Aperture would then create a "virtual copy of these libraries and would be what the users are pointed to, not the real libraries. Potential issue is that if the user doesn't have permissions to access the real library the .strm/symlink might not work? If that is the case, access to the real libraries is granted but "Display in secondary home screen sections such as latest media and continue watching" is disabled for them and is only enabled for the virtual libraries.

Now Aperture could "move" library items around. If any item was in the Top Movies it would get removed from the Virtual Movies library. This way it would only exist in one location at a time. 

 

Potential Downsides:

An item can only exist in one location at a time, meaning if it is in Top library it can't be in the main library or Recommendations library at the same time. Emby global search would alleviate this a bit when looking for a specific item.

If an item was in one users Recommendation it would be removed from everyone's main virtual library. To solve this every user would need their own main virtual libraries

This results in a lot of libraries and access management to deal with. What type of a processing hit might this incur? Database size?

 

Positives:

Full control over all libraries including things liked embedded ratings without modifying the original files

No duplicate entries

 

Not actually expecting that this get implemented, just spewing some thoughts. The problem is that we don't know if Smart Playlists or Home Screen Selections are under active development. The request dates back to 2016 and ETAs have come and gone. It could be 2 weeks, 2 months, or two years.

TheGru
Posted
18 minutes ago, akacharos said:

Well, then I'll start providing some feedback from my usage!
One thing that I see as a privacy concern is that the API endpoints are exposed without a required auth token. I believe API endpoints should be restricted without some authentication.

 

12 minutes ago, akacharos said:

Wait, I'm wrong. It looks like I hit a "error    "Unauthorized" now.
Interesting. So API access is based on browser session?

How API Endpoints Are Protected

Authentication Mechanism: Session-Based with HTTP-Only Cookies

The API uses browser session-based authentication with HTTP-only cookies - you're exactly right!

How It Works

  • Login Flow (apps/api/src/routes/auth.ts😞

    User authenticates via /api/auth/login with their media server (Emby/Jellyfin) credentials

    On successful authentication, a session is created in the database with a 30-day expiry

    A secure HTTP-only cookie (aperture_session) is set containing the session ID

  • Session Validation Plugin (apps/api/src/plugins/auth.ts😞

    Registered globally on all requests via the onRequest hook

    Automatically parses the aperture_session cookie from every request

    Looks up the session in the database and attaches the user to request.user

const authPlugin: FastifyPluginAsync = async (fastify) => {
  // Track if session validation failed (for error messaging)
  fastify.decorateRequest('sessionError', false)

  // Add hook to parse session from cookie
  fastify.addHook('onRequest', async (request) => {
    const sessionId = request.cookies[SESSION_COOKIE_NAME]

    if (sessionId) {
      request.sessionId = sessionId
      try {
        request.user = (await getSessionUser(sessionId)) || undefined
      } catch (err) {
        // ... error handling
      }
    }
  })
}
  • Route Protection Middleware:

    requireAuth: Returns 401 Unauthorized if request.user is not set

    requireAdmin: Returns 401/403 if user isn't authenticated or isn't an admin

// Middleware to require authentication
export async function requireAuth(
  request: FastifyRequest,
  reply: FastifyReply
): Promise<void> {
  if (!request.user) {
    return reply.status(401).send({ error: 'Unauthorized' })
  }
}

// Middleware to require admin
export async function requireAdmin(
  request: FastifyRequest,
  reply: FastifyReply
): Promise<void> {
  // ...
  if (!request.user) {
    return reply.status(401).send({ error: 'Unauthorized' })
  }

  if (!request.user.isAdmin) {
    return reply.status(403).send({ error: 'Forbidden: Admin access required' })
  }
}
  • Applied Per-Route: Every protected route explicitly adds the middleware:
    fastify.get('/api/movies', { preHandler: requireAuth }, async (request, reply) => { ... })
    fastify.get('/api/jobs', { preHandler: requireAdmin }, async (request, reply) => { ... })
    

Public Endpoints (No Auth Required)

A few endpoints are intentionally public:

  • /api/auth/login - Login endpoint
  • /api/auth/login-options - Check if passwordless login is allowed
  • /api/auth/check - Check if currently authenticated
  • /api/health - Health check
  • /api/setup/* - Setup wizard (for first-run configuration)

Cookie Security Properties

  await fastify.register(cookie, {
    secret: process.env.SESSION_SECRET || 'development-secret-change-me',
    parseOptions: {
      httpOnly: true,     // Prevents JavaScript access (XSS protection)
      sameSite: 'lax',    // CSRF protection
      secure: useSecureCookies,  // HTTPS-only when APP_BASE_URL is HTTPS
      path: '/',
    },
  })

TLDR: API access is indeed session-based via browser cookies. When you make API requests from a browser that has logged in, the cookie is automatically sent. External API calls (like from curl or Postman) without the session cookie will get "Unauthorized". This is a secure approach for web applications, protecting against direct API abuse while allowing seamless browser-based access.

akacharos
Posted (edited)

Thanks! I think I can work around the session with storing the cookie string as a variable , although it would be great if we can simplify the admin access to API endpoints with a token key!

Edited by akacharos
TheGru
Posted
5 minutes ago, akacharos said:

Thanks! I think I can work around the session with storing the cookie string as a variable , although it would be great if we can simplify the admin access to API endpoints with a token key!

I figured that was where you were headed. I will update the endpoints to allow token auth and provide an admin interface to generate and expire tokens, and try and do some swagger docs for openapi documentation

That being said I am curious what you plan on doing with the endpoints!

akacharos
Posted
3 hours ago, TheGru said:

I figured that was where you were headed. I will update the endpoints to allow token auth and provide an admin interface to generate and expire tokens, and try and do some swagger docs for openapi documentation

That being said I am curious what you plan on doing with the endpoints!

Mainly playing around with n8n workflows and queries for enhanced chatbot functions.
Currently the chatbot in Aperture is a bit off.
When you ask for "Movies similar to" ... it gives other suggestions from the similar movies you see on the movie details.
Example:
image.thumb.png.681052a25187407445595ae43d2100ce.png
image.thumb.png.a32cc7545e35975b57314cccdcaf12b3.png

Not sure how chat interacts with the APIs tbh, maybe worth investigating.

off-topic: As you can see, image posters in chatbot are not rendered  on my instance, not sure if others can reproduce this.

akacharos
Posted

Potential minor UX issue: When you use the search bar and get results, it immediately focuses on the first returned result.
I'd assume pressing Enter would view all results.
image.png.dfad7af104e56ba1106901b7b07a5f93.png


Also it's unclear what the "AI Search" toggle does , as I always get the same results no matter if it's toggled or not.
image.png.4177549d12b6452f37269a3c1783f93e.png

TheGru
Posted
56 minutes ago, akacharos said:

Mainly playing around with n8n workflows and queries for enhanced chatbot functions.
Currently the chatbot in Aperture is a bit off.
When you ask for "Movies similar to" ... it gives other suggestions from the similar movies you see on the movie details.
Not sure how chat interacts with the APIs tbh, maybe worth investigating.

off-topic: As you can see, image posters in chatbot are not rendered  on my instance, not sure if others can reproduce this.

Almost ready!

image.thumb.png.9cceb1fa9d93101c05c835bfa004840b.png

image.png.77b0e84dc29b6f4085d7e6dee0e64440.png

image.thumb.png.dd623765f1d775b583ef2d8e122bfa1d.png

TheGru
Posted
1 hour ago, akacharos said:

Currently the chatbot in Aperture is a bit off.
When you ask for "Movies similar to" ... it gives other suggestions from the similar movies you see on the movie details.

Looking into it, probably something changed on the details page query that never made it back to the chat tools. 

TheGru
Posted
4 minutes ago, TheGru said:

Looking into it, probably something changed on the details page query that never made it back to the chat tools. 

The details page was leveraging the embeddings in the DB directly. The chat was using semantic search and querying with whatever Provider/Model configured which would yield different results potentially. I have simplified the chat to use the embeddings directly.

akacharos
Posted
35 minutes ago, TheGru said:

Almost ready!

image.thumb.png.9cceb1fa9d93101c05c835bfa004840b.png

image.png.77b0e84dc29b6f4085d7e6dee0e64440.png

image.thumb.png.dd623765f1d775b583ef2d8e122bfa1d.png

wow....API keys and swagger for cherry on top 🙆🏼‍♂️

TheGru
Posted
13 minutes ago, akacharos said:

wow....API keys and swagger for cherry on top 🙆🏼‍♂️

Swagger docs are going to take some time...

TheGru
Posted

I should have built this as a multi-tenant platform on AWS and sold inexpensive monthly subscriptions!

TheGru
Posted

I am thinking about opt-in for a share your emby watch history with other Aperture users as a way to get more top pick variation and potentially other community level enhancement. All anonymized of course

  • Like 1
akacharos
Posted (edited)

For top picks, why re-invent the wheel when you can also utilize trakt endpoints like api.trakt.tv/shows/trending  and api.trakt.tv/movies/trending? I believe those are based on like_count, list_count and comment_count and are updated quite often

What other enhancements are you thinking?

 

Edited by akacharos
TheGru
Posted (edited)
27 minutes ago, akacharos said:

For top picks, why re-invent the wheel when you can also utilize trakt endpoints like api.trakt.tv/shows/trending  and api.trakt.tv/movies/trending? I believe those are based on like_count, list_count and comment_count and are updated quite often

What other enhancements are you thinking?

 

I can certainly do that. My goal is to provide options. 
 

Top picks from:

TMDB: Popular

Trakt: Trending

MDBLists: choose your own lists

Emby: collective user watch history

Aperture: collective community based emby watch history. 

Edited by TheGru
  • Agree 1
akacharos
Posted

I am trying to understand the concept behind "Shows You Watch". I get it that you can add series that already exist in Emby instance and the "Sync to Emby" will generate virtual library.
But I'm not sure, what the benefit is for a virtual library? And why allow adding series that have already ended?

Maybe I am weird, but it would make sense to me if the sync was flipped. Have the Sync button sync FROM Emby the tv shows that are available and SeriesInProgress = true for the user.
That way users can see which shows they haven't finished watching, so it's real list of what they are actively watching, not just a subset of the library they manually picked.

And to get wild with ideas, Aperture could detect which of those in-progress shows are missing seasons in the Emby library. Then integrate with Jellyseerr so users request their missing seasons right from the "Shows You Watch" section.

If I'm talking non-sense of getting too wild with ideas, just ignore me!

akacharos
Posted
50 minutes ago, TheGru said:

I can certainly do that. My goal is to provide options. 
 

Top picks from:

TMDB: Popular

Trakt: Trending

MDBLists: choose your own lists

Emby: collective user watch history

Aperture: collective community based emby watch history. 

The Emby/Aperture user watch history would certainly help with the collaborative filtering direction.
And it can be optional in Aperture were you can opt-in for the Aperture collective watching or stick to your userbase

  • Agree 1
Posted
17 hours ago, TheGru said:

I am thinking about opt-in for a share your emby watch history with other Aperture users as a way to get more top pick variation and potentially other community level enhancement. All anonymized of course

I would consult with @TeamB I believe he attempted that very thing with PlaybackReporting and found it not worth it.

  • Thanks 1
TheGru
Posted
1 hour ago, akacharos said:

I am trying to understand the concept behind "Shows You Watch". I get it that you can add series that already exist in Emby instance and the "Sync to Emby" will generate virtual library.
But I'm not sure, what the benefit is for a virtual library? And why allow adding series that have already ended?

Maybe I am weird, but it would make sense to me if the sync was flipped. Have the Sync button sync FROM Emby the tv shows that are available and SeriesInProgress = true for the user.
That way users can see which shows they haven't finished watching, so it's real list of what they are actively watching, not just a subset of the library they manually picked.

And to get wild with ideas, Aperture could detect which of those in-progress shows are missing seasons in the Emby library. Then integrate with Jellyseerr so users request their missing seasons right from the "Shows You Watch" section.

If I'm talking non-sense of getting too wild with ideas, just ignore me!

📺 Shows You Watch: Your Personal DVR-Style Home Row (Finally, No More Noise!)

Let me explain a feature that's a possible game-changer for multi-user households: Shows You Watch.

The Problem

If you're like me, you've got multiple users on your system—family members, roommates, whoever—and they all request content. That's great! But here's what happens:

Latest Shows becomes a complete mess.

My wife is watching three different reality shows. My kids are into anime. My buddy who I gave access to is binging some crime documentary series. And me? I'm just trying to keep up with the two or three shows I actually care about.

The result? The shows I'm actively following get buried under a mountain of content I'll never watch. I'm scrolling through 30+ items just to find the one show I want to continue. It's exhausting.

The Solution: Shows You Watch

Think of Shows You Watch as a pseudo-DVR home row — but smarter.

Here's the concept: You mark the shows YOU actually care about in Aperture, and Aperture creates a custom library that displays ONLY those items. No noise. No clutter. Just your shows.

What You Get:

  • A dedicated "Shows You Watch" section on your home screen with only the series you're following
  • Next episode tracking in Aperture — see exactly what's coming up and when
  • Progress indicators In Aperture — know where you left off at a glance
  • "Days until" countdowns In Aperture — "Tomorrow", "In 3 days", etc.
  • Behind count — if you're 5 episodes behind, you'll know

How It Works:

  • The system tracks what you've been watching recently
  • Only continuing (not ended) series qualify
  • Your personal "Shows You Watch" library gets created automatically
  • This library appears in both Aperture AND your media server (Emby)

The best part? It's per-user. My wife has her Shows You Watch, I have mine. We're not stepping on each other's toes.

The Virtual Library Bonus

Here's where it gets really nice: Shows You Watch creates an actual library in your media server called something like "Shows You Watch - YourName".

So even when you're browsing directly in Emby (not through Aperture), you've got quick one-click access to continue your shows. It shows up right on your home screen. No more hunting.

If you're running a multi-user setup and haven't explored this feature yet, give it a shot. It's the difference between your media server feeling like a chaotic shared Netflix account vs. your own personalized DVR.

Posted
22 minutes ago, TheGru said:
  • A dedicated "Shows You Watch" section on your home screen with only the series you're following
  • Next episode tracking in Aperture — see exactly what's coming up and when
  • Progress indicators In Aperture — know where you left off at a glance
  • "Days until" countdowns In Aperture — "Tomorrow", "In 3 days", etc.
  • Behind count — if you're 5 episodes behind, you'll know

Doesn't Next Up/Continue Watching already do all of this except for "Days Until"?

TheGru
Posted
31 minutes ago, ebr said:

Doesn't Next Up/Continue Watching already do all of this except for "Days Until"?

it may but with all the duplicates in continue watching I have that disabled on my server, and am using this as a workaround

Jdiesel
Posted (edited)

Interesting! So it sounds like you've disabled Embys Up Next/Continue Watching functionality for each library and replicated it, plus more, in Aperture. Does Aperture need to run a scheduled task to update this new library? If so, how often does it run by default?

Edited by Jdiesel
TheGru
Posted
16 minutes ago, Jdiesel said:

Interesting! So it sounds like you've disabled Embys Up Next/Continue Watching functionality for each library and replicated it, plus more, in Aperture. Does Aperture need to run a scheduled task to update this new library? If so, how often does it run by default?

I believe these are the defaults, but you have full control to adjust schedules for all jobs except the ones that reset things

image.thumb.png.6f50613e5d8637ffaf23b01b9e53669f.png

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...