Bouton ✕ sur les films notés 10/10 pour supprimer la note via DELETE /api/rate/:id. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
12
main.py
12
main.py
@@ -187,4 +187,16 @@ async def rate_movie(request: Request, trakt_id: int, body: RateBody):
|
|||||||
return {"success": True}
|
return {"success": True}
|
||||||
|
|
||||||
|
|
||||||
|
@app.delete("/api/rate/{trakt_id}")
|
||||||
|
async def remove_rating(request: Request, trakt_id: int):
|
||||||
|
token = request.session.get("access_token")
|
||||||
|
if not token:
|
||||||
|
raise HTTPException(401, "Not authenticated")
|
||||||
|
|
||||||
|
trakt = TraktClient(TRAKT_CLIENT_ID, token)
|
||||||
|
await trakt.remove_rating(trakt_id)
|
||||||
|
cache_del(f"movies_{token[:16]}")
|
||||||
|
return {"success": True}
|
||||||
|
|
||||||
|
|
||||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||||
|
|||||||
@@ -160,9 +160,11 @@ function buildRow(movie) {
|
|||||||
).join('');
|
).join('');
|
||||||
|
|
||||||
const skipLabel = isSkipped ? 'Remettre' : 'Passer';
|
const skipLabel = isSkipped ? 'Remettre' : 'Passer';
|
||||||
const skipBtn = `<button class="skip-btn" title="${skipLabel}">${skipLabel}</button>`;
|
const skipBtn = `<button class="skip-btn">${skipLabel}</button>`;
|
||||||
|
const removeBtn = movie.current_rating !== null
|
||||||
|
? `<button class="remove-btn" title="Supprimer la note">✕</button>` : '';
|
||||||
|
|
||||||
const ratingEl = `<div class="movie-rating">${btns}${skipBtn}</div>`;
|
const ratingEl = `<div class="movie-rating">${btns}${removeBtn}${skipBtn}</div>`;
|
||||||
|
|
||||||
row.innerHTML = poster + info + synopsis + ratingEl;
|
row.innerHTML = poster + info + synopsis + ratingEl;
|
||||||
|
|
||||||
@@ -196,6 +198,12 @@ function buildRow(movie) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove rating button
|
||||||
|
const removeBtnEl = container.querySelector('.remove-btn');
|
||||||
|
if (removeBtnEl) {
|
||||||
|
removeBtnEl.addEventListener('click', () => removeRating(movie, row));
|
||||||
|
}
|
||||||
|
|
||||||
// Skip button
|
// Skip button
|
||||||
container.querySelector('.skip-btn').addEventListener('click', () => {
|
container.querySelector('.skip-btn').addEventListener('click', () => {
|
||||||
if (isSkipped) {
|
if (isSkipped) {
|
||||||
@@ -211,6 +219,20 @@ function buildRow(movie) {
|
|||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Remove rating ──────────────────────────────────────── */
|
||||||
|
async function removeRating(movie, row) {
|
||||||
|
row.style.pointerEvents = 'none';
|
||||||
|
try {
|
||||||
|
const r = await fetch(`/api/rate/${movie.trakt_id}`, { method: 'DELETE' });
|
||||||
|
if (!r.ok) throw new Error('Failed');
|
||||||
|
showToast(`${movie.title_fr} — note supprimée`);
|
||||||
|
animateOut(row);
|
||||||
|
} catch {
|
||||||
|
row.style.pointerEvents = '';
|
||||||
|
showToast('Erreur lors de la suppression', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Rate ───────────────────────────────────────────────── */
|
/* ── Rate ───────────────────────────────────────────────── */
|
||||||
async function rateMovie(movie, rating, row) {
|
async function rateMovie(movie, rating, row) {
|
||||||
row.style.pointerEvents = 'none';
|
row.style.pointerEvents = 'none';
|
||||||
|
|||||||
@@ -316,6 +316,24 @@ main {
|
|||||||
}
|
}
|
||||||
.r-btn:active { transform: scale(.92); }
|
.r-btn:active { transform: scale(.92); }
|
||||||
|
|
||||||
|
.remove-btn {
|
||||||
|
margin-left: 6px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid rgba(244,63,94,.25);
|
||||||
|
background: transparent;
|
||||||
|
color: #f87191;
|
||||||
|
font-size: .75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit;
|
||||||
|
transition: border-color .15s, background .15s;
|
||||||
|
}
|
||||||
|
.remove-btn:hover {
|
||||||
|
border-color: rgba(244,63,94,.5);
|
||||||
|
background: rgba(244,63,94,.1);
|
||||||
|
}
|
||||||
|
|
||||||
.skip-btn {
|
.skip-btn {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
padding: 0 9px;
|
padding: 0 9px;
|
||||||
|
|||||||
10
trakt.py
10
trakt.py
@@ -23,6 +23,16 @@ class TraktClient:
|
|||||||
ratings_r.raise_for_status()
|
ratings_r.raise_for_status()
|
||||||
return watched_r.json(), ratings_r.json()
|
return watched_r.json(), ratings_r.json()
|
||||||
|
|
||||||
|
async def remove_rating(self, trakt_id: int):
|
||||||
|
async with httpx.AsyncClient(timeout=30) as client:
|
||||||
|
r = await client.post(
|
||||||
|
f"{self.BASE_URL}/sync/ratings/remove",
|
||||||
|
headers=self.headers,
|
||||||
|
json={"movies": [{"ids": {"trakt": trakt_id}}]},
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.json()
|
||||||
|
|
||||||
async def rate_movie(self, trakt_id: int, rating: int):
|
async def rate_movie(self, trakt_id: int, rating: int):
|
||||||
async with httpx.AsyncClient(timeout=30) as client:
|
async with httpx.AsyncClient(timeout=30) as client:
|
||||||
r = await client.post(
|
r = await client.post(
|
||||||
|
|||||||
Reference in New Issue
Block a user