Skip to content

Commit d2df3cd

Browse files
committed
feat: add bulk completion date setting #802
Add user preference to control what date is used when marking seasons or TV shows as completed. Options: Current Date (default), Release Date, or No Date. Useful for adding historical media without affecting statistics.
1 parent bb083ef commit d2df3cd

File tree

5 files changed

+104
-1
lines changed

5 files changed

+104
-1
lines changed

src/app/models.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,8 @@ def get_remaining_eps(self, season_metadata):
14141414
latest_watched_ep_num = 0
14151415

14161416
episodes_to_create = []
1417+
1418+
# Calculate current time once before the loop
14171419
now = timezone.now().replace(second=0, microsecond=0)
14181420

14191421
# Create Episode objects for the remaining episodes
@@ -1423,10 +1425,13 @@ def get_remaining_eps(self, season_metadata):
14231425

14241426
item = self.get_episode_item(episode["episode_number"], season_metadata)
14251427

1428+
# Resolve end_date based on user preference
1429+
end_date = self.user.resolve_watch_date(now, episode.get("air_date"))
1430+
14261431
episode_db = Episode(
14271432
related_season=self,
14281433
item=item,
1429-
end_date=now,
1434+
end_date=end_date,
14301435
)
14311436
episodes_to_create.append(episode_db)
14321437

src/static/css/main.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,9 @@
795795
.flex-1 {
796796
flex: 1;
797797
}
798+
.flex-shrink-0 {
799+
flex-shrink: 0;
800+
}
798801
.shrink-0 {
799802
flex-shrink: 0;
800803
}
@@ -2279,6 +2282,16 @@
22792282
--tw-ring-color: var(--color-indigo-200);
22802283
}
22812284
}
2285+
.focus\:ring-indigo-300 {
2286+
&:focus {
2287+
--tw-ring-color: var(--color-indigo-300);
2288+
}
2289+
}
2290+
.focus\:ring-indigo-400 {
2291+
&:focus {
2292+
--tw-ring-color: var(--color-indigo-400);
2293+
}
2294+
}
22822295
.focus\:ring-indigo-500 {
22832296
&:focus {
22842297
--tw-ring-color: var(--color-indigo-500);

src/templates/users/ui_preferences.html

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,28 @@ <h2 class="text-xl font-semibold">UI Preferences</h2>
4040
</div>
4141
</div>
4242

43+
{# Quick Watch Date #}
44+
<div class="mb-5">
45+
<div class="flex items-center justify-between p-3 bg-[#39404b] rounded-md">
46+
<div class="flex-1">
47+
<div class="flex items-center text-gray-200 mb-1">
48+
{% include "app/icons/clock.svg" with classes="w-5 h-5 mr-2" %}
49+
<span class="text-sm font-medium">Bulk Completion Date</span>
50+
</div>
51+
<p class="text-xs text-gray-400 ml-7">
52+
When marking a TV show or season as completed, its episodes will be marked as completed with this date.
53+
</p>
54+
</div>
55+
<select name="quick_watch_date"
56+
class="ml-4 p-2 bg-[#39404b] rounded-md text-white text-sm border border-gray-600 focus:outline-none focus:ring-2 focus:ring-indigo-400">
57+
{% for choice in quick_watch_date_choices %}
58+
<option value="{{ choice.0 }}"
59+
{% if user.quick_watch_date == choice.0 %}selected{% endif %}>{{ choice.1 }}</option>
60+
{% endfor %}
61+
</select>
62+
</div>
63+
</div>
64+
4365
<div class="border-t border-gray-600 my-5"></div>
4466

4567
{# Media Types Settings #}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated by Django 5.2.9 on 2026-01-17 16:11
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('app', '0052_alter_item_title'),
10+
('auth', '0012_alter_user_first_name_max_length'),
11+
('users', '0040_user_list_detail_status'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='user',
17+
name='quick_watch_date',
18+
field=models.CharField(choices=[('current_date', 'Current Date'), ('release_date', 'Release Date'), ('no_date', 'No Date')], default='current_date', help_text='Date to use when bulk-marking media as completed', max_length=20),
19+
),
20+
migrations.AddConstraint(
21+
model_name='user',
22+
constraint=models.CheckConstraint(condition=models.Q(('quick_watch_date__in', ['current_date', 'release_date', 'no_date'])), name='quick_watch_date_valid'),
23+
),
24+
]

src/users/models.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ class ListDetailSortChoices(models.TextChoices):
8282
MEDIA_TYPE = "media_type", "Media Type"
8383

8484

85+
class QuickWatchDateChoices(models.TextChoices):
86+
"""Choices for quick watch date behavior when bulk-marking media as completed."""
87+
88+
CURRENT_DATE = "current_date", "Current Date"
89+
RELEASE_DATE = "release_date", "Release Date"
90+
NO_DATE = "no_date", "No Date"
91+
92+
8593
class User(AbstractUser):
8694
"""Custom user model."""
8795

@@ -249,6 +257,13 @@ class User(AbstractUser):
249257
help_text="Hide hover overlay on touch devices",
250258
)
251259

260+
# Tracking settings
261+
quick_watch_date = models.CharField(
262+
max_length=20,
263+
default=QuickWatchDateChoices.CURRENT_DATE,
264+
choices=QuickWatchDateChoices.choices,
265+
help_text="Date to use when bulk-marking media as completed",
266+
)
252267
# Calendar preferences
253268
calendar_layout = models.CharField(
254269
max_length=20,
@@ -418,6 +433,10 @@ class Meta:
418433
name="book_status_valid",
419434
condition=models.Q(book_status__in=MediaStatusChoices.values),
420435
),
436+
models.CheckConstraint(
437+
name="quick_watch_date_valid",
438+
condition=models.Q(quick_watch_date__in=QuickWatchDateChoices.values),
439+
),
421440
]
422441

423442
def update_preference(self, field_name, new_value):
@@ -459,6 +478,26 @@ def update_preference(self, field_name, new_value):
459478

460479
return new_value
461480

481+
def resolve_watch_date(self, now, release_date):
482+
"""
483+
Resolve the appropriate watch date based on user preference.
484+
485+
Args:
486+
now: Pre-calculated current datetime
487+
release_date: The release/air date for the specific media item
488+
489+
Returns:
490+
datetime or None based on user preference
491+
"""
492+
if self.quick_watch_date == QuickWatchDateChoices.NO_DATE:
493+
return None
494+
495+
if self.quick_watch_date == QuickWatchDateChoices.RELEASE_DATE:
496+
return release_date # Will be None if not available in metadata
497+
498+
# CURRENT_DATE is the default
499+
return now
500+
462501
def get_enabled_media_types(self):
463502
"""Return a list of enabled media type values based on user preferences."""
464503
enabled_types = []

0 commit comments

Comments
 (0)