Skip to content

Commit 59cbb30

Browse files
committed
Prevent showing same pait twice in a row
1 parent 4a300c5 commit 59cbb30

File tree

1 file changed

+98
-45
lines changed

1 file changed

+98
-45
lines changed

db/database.py

Lines changed: 98 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ def __init__(self, db_path: str = None):
3535
self._create_indices()
3636
self._ensure_default_album()
3737

38+
self.last_pairs = {}
39+
3840
def _create_indices(self):
3941
"""Create indices for efficient sorting and filtering."""
4042
indices = [
@@ -738,69 +740,120 @@ def delete_votes(self, vote_ids: List[int]):
738740

739741
def get_pair_for_voting(self, album_id: int = 1) -> Tuple[Optional[tuple], Optional[tuple]]:
740742
"""
741-
Get two media items for voting with adaptive rating difference handling.
743+
Get voting pair with duplicate prevention
742744
"""
743745
media_count = self.get_total_media_count(album_id)
744-
total_votes = self.get_total_votes(album_id)
745-
reliability = ReliabilityCalculator.calculate_reliability(media_count, total_votes)
746+
if media_count < 2:
747+
return None, None
746748

747-
# Get least voted item
748-
self.cursor.execute("""
749+
# Get least voted item excluding last pair
750+
least_voted = self._get_least_voted(album_id)
751+
if not least_voted:
752+
return None, None
753+
754+
# Get second item with duplicate prevention
755+
second_item = self._get_second_item(album_id, least_voted)
756+
757+
# Update last pair tracking
758+
if least_voted and second_item:
759+
self.last_pairs[album_id] = (least_voted[0], second_item[0])
760+
761+
return least_voted, second_item
762+
763+
def _get_least_voted(self, album_id: int):
764+
"""Get least voted item excluding last pair components"""
765+
exclude_ids = list(self.last_pairs.get(album_id, ()))
766+
767+
# Build exclusion clause
768+
exclude_clause = ""
769+
params = [album_id]
770+
if exclude_ids:
771+
placeholders = ",".join(["?"] * len(exclude_ids))
772+
exclude_clause = f"AND id NOT IN ({placeholders})"
773+
params += exclude_ids
774+
775+
query = f"""
749776
SELECT id, path, rating, votes
750777
FROM media
751778
WHERE album_id = ?
752-
ORDER BY votes ASC, RANDOM()
779+
{exclude_clause}
780+
ORDER BY votes ASC, RANDOM()
753781
LIMIT 1
754-
""", (album_id,))
755-
least_voted = self.cursor.fetchone()
782+
"""
756783

757-
if not least_voted:
758-
return None, None
784+
self.cursor.execute(query, params)
785+
return self.cursor.fetchone()
759786

760-
# Adaptive rating difference logic
761-
if reliability >= 85:
762-
# Try to find closest match first, then gradually expand search
763-
self.cursor.execute("""
764-
SELECT id, path, rating, votes
765-
FROM media
766-
WHERE id != ?
767-
AND album_id = ?
768-
ORDER BY
769-
CASE
770-
WHEN ABS(rating - ?) <= 100 THEN 0
771-
WHEN ABS(rating - ?) <= 200 THEN 1
772-
ELSE 2
773-
END,
774-
ABS(rating - ?) ASC,
775-
RANDOM()
776-
LIMIT 1
777-
""", (least_voted[0], album_id, least_voted[2], least_voted[2], least_voted[2]))
778-
else:
779-
# Random selection for early stages
780-
self.cursor.execute("""
781-
SELECT id, path, rating, votes
782-
FROM media
783-
WHERE id != ?
784-
AND album_id = ?
785-
ORDER BY RANDOM()
786-
LIMIT 1
787-
""", (least_voted[0], album_id))
787+
def _get_second_item(self, album_id: int, least_voted: tuple):
788+
"""Get second item with adaptive logic and duplicate prevention"""
789+
media_count = self.get_total_media_count(album_id)
790+
total_votes = self.get_total_votes(album_id)
791+
reliability = ReliabilityCalculator.calculate_reliability(media_count, total_votes)
788792

789-
second_item = self.cursor.fetchone()
793+
exclude_ids = list(self.last_pairs.get(album_id, []))
794+
exclude_ids.append(least_voted[0])
790795

791-
# Fallback if no matches found (should never happen with at least 2 items)
792-
if not second_item:
793-
self.cursor.execute("""
796+
# Build exclusion parameters
797+
exclude_clause = ""
798+
base_params = [least_voted[0], album_id]
799+
if exclude_ids:
800+
placeholders = ",".join(["?"] * len(exclude_ids))
801+
exclude_clause = f"AND id NOT IN ({placeholders})"
802+
base_params += exclude_ids
803+
804+
if reliability >= 85:
805+
# Try different tiers with exclusion
806+
for max_diff in [100, 200, None]:
807+
rating_clause = ""
808+
order_clause = "RANDOM()"
809+
params = base_params.copy()
810+
811+
if max_diff:
812+
rating_clause = "AND ABS(rating - ?) <= ?"
813+
order_clause = "ABS(rating - ?) ASC, RANDOM()"
814+
params += [least_voted[2], max_diff, least_voted[2]]
815+
816+
query = f"""
817+
SELECT id, path, rating, votes
818+
FROM media
819+
WHERE id != ?
820+
AND album_id = ?
821+
{exclude_clause}
822+
{rating_clause}
823+
ORDER BY {order_clause}
824+
LIMIT 1
825+
"""
826+
827+
self.cursor.execute(query, params)
828+
result = self.cursor.fetchone()
829+
if result:
830+
return result
831+
else:
832+
# Random selection with exclusion
833+
query = f"""
794834
SELECT id, path, rating, votes
795835
FROM media
796836
WHERE id != ?
797837
AND album_id = ?
838+
{exclude_clause}
798839
ORDER BY RANDOM()
799840
LIMIT 1
800-
""", (least_voted[0], album_id))
801-
second_item = self.cursor.fetchone()
841+
"""
842+
self.cursor.execute(query, base_params)
843+
return self.cursor.fetchone()
802844

803-
return least_voted, second_item
845+
# Fallback if all queries failed
846+
query = f"""
847+
SELECT id, path, rating, votes
848+
FROM media
849+
WHERE id != ?
850+
AND album_id = ?
851+
{exclude_clause}
852+
ORDER BY RANDOM()
853+
LIMIT 1
854+
"""
855+
self.cursor.execute(query, base_params)
856+
return self.cursor.fetchone()
804857

805858
def close(self):
806859
"""Close the database connection."""

0 commit comments

Comments
 (0)