Skip to content

Commit df9cc4e

Browse files
committed
Add user preference for showing adult titles.
1 parent d1eed95 commit df9cc4e

9 files changed

Lines changed: 85 additions & 20 deletions

File tree

src/app/providers/igdb.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,9 @@ def external_game(external_id, source=ExternalGameSource.STEAM):
175175
return data
176176

177177

178-
def search(query, page):
178+
def search(query, page, show_adult_titles=False): # noqa: FBT002
179179
"""Search for games on IGDB using MultiQuery."""
180-
cache_key = f"search_{Sources.IGDB.value}_{MediaTypes.GAME.value}_{query}_{page}"
180+
cache_key = f"search_{Sources.IGDB.value}_{MediaTypes.GAME.value}_{query}_{page}_{show_adult_titles}" # noqa: E501
181181
data = cache.get(cache_key)
182182

183183
if data is None:
@@ -192,7 +192,7 @@ def search(query, page):
192192
f'where name ~ *"{query}"* & game_type = (0,1,2,3,4,5,6,7,8,9,10)'
193193
)
194194

195-
if not settings.IGDB_NSFW:
195+
if not settings.IGDB_NSFW or not show_adult_titles:
196196
base_conditions += " & themes != (42)"
197197

198198
offset = (page - 1) * settings.PER_PAGE

src/app/providers/mal.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ def handle_error(error):
4040
raise services.ProviderAPIError(Sources.MAL.value, error)
4141

4242

43-
def search(media_type, query, page):
43+
def search(media_type, query, page, show_adult_titles=False): # noqa: FBT002
4444
"""Search for media on MyAnimeList."""
45-
cache_key = f"search_{Sources.MAL.value}_{media_type}_{query}_{page}"
45+
cache_key = (
46+
f"search_{Sources.MAL.value}_{media_type}_{query}_{page}_{show_adult_titles}"
47+
)
4648
data = cache.get(cache_key)
4749

4850
if data is None:
@@ -52,7 +54,7 @@ def search(media_type, query, page):
5254
"fields": "media_type",
5355
"limit": settings.PER_PAGE,
5456
}
55-
if settings.MAL_NSFW:
57+
if settings.MAL_NSFW and show_adult_titles:
5658
params["nsfw"] = "true"
5759

5860
try:

src/app/providers/services.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,20 +245,30 @@ def get_media_metadata(
245245
return metadata_retrievers[media_type]()
246246

247247

248-
def search(media_type, query, page, source=None):
248+
def search(media_type, query, page, source=None, show_adult_titles=False): # noqa: FBT002
249249
"""Search for media based on the query and return the results."""
250250
search_handlers = {
251251
MediaTypes.MANGA.value: lambda: (
252252
mangaupdates.search(query, page)
253253
if source == Sources.MANGAUPDATES.value
254-
else mal.search(media_type, query, page)
254+
else mal.search(media_type, query, page, show_adult_titles)
255255
),
256-
MediaTypes.ANIME.value: lambda: mal.search(media_type, query, page),
257-
MediaTypes.TV.value: lambda: tmdb.search(media_type, query, page),
258-
MediaTypes.MOVIE.value: lambda: tmdb.search(media_type, query, page),
259-
MediaTypes.SEASON.value: lambda: tmdb.search(MediaTypes.TV.value, query, page),
260-
MediaTypes.EPISODE.value: lambda: tmdb.search(MediaTypes.TV.value, query, page),
261-
MediaTypes.GAME.value: lambda: igdb.search(query, page),
256+
MediaTypes.ANIME.value: lambda: mal.search(
257+
media_type, query, page, show_adult_titles
258+
),
259+
MediaTypes.TV.value: lambda: tmdb.search(
260+
media_type, query, page, show_adult_titles
261+
),
262+
MediaTypes.MOVIE.value: lambda: tmdb.search(
263+
media_type, query, page, show_adult_titles
264+
),
265+
MediaTypes.SEASON.value: lambda: tmdb.search(
266+
MediaTypes.TV.value, query, page, show_adult_titles
267+
),
268+
MediaTypes.EPISODE.value: lambda: tmdb.search(
269+
MediaTypes.TV.value, query, page, show_adult_titles
270+
),
271+
MediaTypes.GAME.value: lambda: igdb.search(query, page, show_adult_titles),
262272
MediaTypes.BOOK.value: lambda: (
263273
openlibrary.search(query, page)
264274
if source == Sources.OPENLIBRARY.value

src/app/providers/tmdb.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ def get_external_links(external_ids, tmdb_id=None):
6868
return links
6969

7070

71-
def search(media_type, query, page):
71+
def search(media_type, query, page, show_adult_titles=False): # noqa: FBT002
7272
"""Search for media on TMDB."""
73-
cache_key = f"search_{Sources.TMDB.value}_{media_type}_{query}_{page}"
73+
cache_key = (
74+
f"search_{Sources.TMDB.value}_{media_type}_{query}_{page}_{show_adult_titles}"
75+
)
7476
data = cache.get(cache_key)
7577

7678
if data is None:
@@ -82,7 +84,7 @@ def search(media_type, query, page):
8284
"page": page,
8385
}
8486

85-
if settings.TMDB_NSFW:
87+
if settings.TMDB_NSFW and show_adult_titles:
8688
params["include_adult"] = "true"
8789

8890
try:
@@ -237,8 +239,7 @@ def movie(media_id):
237239
),
238240
},
239241
"external_links": get_external_links(
240-
response.get("external_ids", {}),
241-
media_id
242+
response.get("external_ids", {}), media_id
242243
),
243244
"providers": response.get("watch/providers", {}).get("results", {}),
244245
}

src/app/views.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,13 @@ def media_search(request):
175175
config.get_default_source_name(media_type).value,
176176
)
177177

178-
data = services.search(media_type, query, page, source)
178+
data = services.search(
179+
media_type,
180+
query,
181+
page,
182+
source,
183+
show_adult_titles=request.user.show_adult_titles,
184+
)
179185

180186
# Enrich search results with user tracking data
181187
if data.get("results"):

src/templates/users/preferences.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,27 @@ <h2 class="text-xl font-semibold">Preferences</h2>
191191
</div>
192192
</div>
193193

194+
{# Show adult titles #}
195+
<div class="mb-5">
196+
<div class="flex items-center justify-between p-3 bg-[#39404b] rounded-md">
197+
<div class="flex-1">
198+
<div class="flex items-center text-gray-200 mb-1">
199+
{% include "app/icons/shield-alert.svg" with classes="w-5 h-5 mr-2" %}
200+
<span class="text-sm font-medium">Show adult titles</span>
201+
</div>
202+
<p class="text-xs text-gray-400 ml-7">Show adult titles in searches. Depends on them being enabled by the server.</p>
203+
</div>
204+
<label class="relative inline-flex items-center cursor-pointer ml-4">
205+
<input class="sr-only peer"
206+
type="checkbox"
207+
name="show_adult_titles"
208+
{% if user.show_adult_titles %}checked{% endif %}>
209+
<div class="w-9 h-5 bg-gray-600 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-px after:left-0.5 after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4.5 after:w-4.5 after:transition-all peer-checked:bg-indigo-600">
210+
</div>
211+
</label>
212+
</div>
213+
</div>
214+
194215
<div class="border-t border-gray-600 my-5"></div>
195216

196217
{# Media Types Settings #}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.2.11 on 2026-03-08 15:02
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('users', '0050_user_watch_provider_region'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='user',
15+
name='show_adult_titles',
16+
field=models.BooleanField(default=False, help_text='Show adult titles'),
17+
),
18+
]

src/users/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@ class User(AbstractUser):
393393
help_text="Comma-separated list of Plex usernames for webhook matching",
394394
)
395395

396+
show_adult_titles = models.BooleanField(
397+
default=False,
398+
help_text="Show adult titles",
399+
)
400+
396401
class Meta:
397402
"""Meta options for the model."""
398403

src/users/views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,8 @@ def preferences(request):
253253
"time_format",
254254
TimeFormatChoices.HOUR_24,
255255
)
256+
request.user.show_adult_titles = "show_adult_titles" in request.POST
257+
256258
media_types_checked = request.POST.getlist("media_types_checkboxes")
257259

258260
provider_region = request.POST.get("watch_provider_region", "")

0 commit comments

Comments
 (0)