Created
January 18, 2026 20:21
-
-
Save JulienRAVIA/f7e7bd3e63e61a2b8a9aa92b586e0e8e to your computer and use it in GitHub Desktop.
SensCritique
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name SensCritique - Ajouter au calendrier Google | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.0 | |
| // @description Ajoute un bouton "Ajouter au calendrier" pour chaque film sur les pages de sorties cinéma SensCritique | |
| // @author JulienRAVIA | |
| // @match https://www.senscritique.com/films/sorties-cinema/*/semaine/* | |
| // @match https://www.senscritique.com/films/sorties-cinema/*/* | |
| // @match https://www.senscritique.com/films/sorties-cinema/* | |
| // @match https://www.senscritique.com/films/cette-semaine | |
| // @icon https://www.senscritique.com/favicon.ico | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // Fonction pour formater la date pour Google Calendar (YYYYMMDD) | |
| function formatDateForGoogle(date) { | |
| const year = date.getFullYear(); | |
| const month = String(date. getMonth() + 1).padStart(2, '0'); | |
| const day = String(date. getDate()).padStart(2, '0'); | |
| return `${year}${month}${day}`; | |
| } | |
| // Fonction pour formater la date en français | |
| function formatDate(date) { | |
| const moisFrancais = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', | |
| 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre']; | |
| const parts = date.trim().split(' '); | |
| const jour = parts[0]; | |
| const mois = moisFrancais.indexOf(parts[1].toLowerCase()) + 1; | |
| const annee = parts[2]; | |
| return new Date(annee, mois - 1, jour); | |
| } | |
| // Fonction pour créer le lien Google Calendar | |
| function createGoogleCalendarLink(title, date, synopsis, creators, otherInfos, url) { | |
| const dateStr = formatDateForGoogle(date); | |
| const params = new URLSearchParams({ | |
| action: 'TEMPLATE', | |
| text: `${title}`, | |
| dates: `${dateStr}/${dateStr}`, | |
| details: `${otherInfos}.\n\n${creators}.\n\n${synopsis}.\n\n<a href="${url}">${url}</a>`, | |
| ctz: 'Europe/Paris' | |
| }); | |
| return `https://calendar.google.com/calendar/render?${params. toString()}`; | |
| } | |
| // Fonction pour ajouter les boutons calendrier | |
| function addCalendarButtons() { | |
| // Sélectionner tous les éléments de film | |
| // SensCritique utilise généralement des cartes pour afficher les films | |
| const filmCards = document.querySelectorAll('[data-testid="product-list-item"]'); | |
| // Si pas de cartes trouvées, essayer une approche plus générique | |
| let films = []; | |
| if (filmCards.length === 0) { | |
| // Chercher les liens vers les films | |
| const filmLinks = document.querySelectorAll('a[href^="/film/"]'); | |
| const processedTitles = new Set(); | |
| filmLinks.forEach(link => { | |
| const title = link.textContent.trim(); | |
| if (title && !processedTitles.has(title) && title. length > 1) { | |
| // Trouver le conteneur parent le plus proche | |
| let container = link.closest('li, article, div[class*="card"], div[class*="Card"], div[class*="item"], div[class*="Item"]'); | |
| if (container && ! container.querySelector('. sc-calendar-btn')) { | |
| films.push({ element: container, title: title, link: link }); | |
| processedTitles.add(title); | |
| } | |
| } | |
| }); | |
| } else { | |
| filmCards.forEach(card => { | |
| if (card.querySelector('.sc-calendar-btn')) return; | |
| const titleElement = card.querySelector('[data-testid="product-title"]'); | |
| const url = titleElement.href; | |
| const title = titleElement ? titleElement. textContent.trim() : null; | |
| const cleanedTitle = title.replace(/\s*\(\d{4}\)/, '').trim(); | |
| const synopsis = card.querySelector('[data-testid="content"]')?.textContent.trim(); | |
| const creators = card.querySelector('[data-testid="creators"]')?.textContent.trim(); | |
| const otherInfos = card.querySelector('[data-testid="other-infos"]')?.textContent.trim(); | |
| const releaseDate = card.querySelector('[data-testid="date-release"]')?.textContent.trim(); | |
| const cleaned = releaseDate.replace('.', '').replace('Sortie : ', '').replace(/\s*\([^)]*\)/g, ''); | |
| if (title) { | |
| films.push({ element: card, title: cleanedTitle, synopsis, otherInfos, creators, releaseDate: cleaned, url }); | |
| } | |
| }); | |
| } | |
| // Ajouter les boutons pour chaque film | |
| films.forEach(film => { | |
| if (film.element.querySelector('.sc-calendar-btn')) return; | |
| const dateSortie = formatDate(film.releaseDate); | |
| const calendarLink = createGoogleCalendarLink(film.title, dateSortie, film.synopsis, film.creators, film.otherInfos, film.url); | |
| // Créer le conteneur du bouton | |
| const buttonContainer = document.createElement('div'); | |
| buttonContainer.className = 'sc-calendar-btn'; | |
| buttonContainer.style.cssText = ` | |
| margin-top: 8px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 4px; | |
| `; | |
| // Créer le bouton | |
| const button = document.createElement('a'); | |
| button.href = calendarLink; | |
| button.target = '_blank'; | |
| button. rel = 'noopener noreferrer'; | |
| button.textContent = 'Ajouter au calendrier'; | |
| button.style.cssText = ` | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 4px; | |
| padding: 6px 12px; | |
| color: rgb(52, 64, 84); | |
| text-transform: uppercase; | |
| text-decoration: none; | |
| border-radius: 4px; | |
| border: 1px solid rgb(208, 213, 221); | |
| font-size: 12px; | |
| font-weight: 500; | |
| transition: all 0.2s ease; | |
| background: rgb(250, 249, 246); | |
| font-family: var(--font-sourceCodePro); | |
| width: fit-content; | |
| `; | |
| button.addEventListener('mouseenter', () => { | |
| button.style.transform = 'translateY(-1px)'; | |
| button.style.boxShadow = '0 4px 8px rgba(0,0,0,0. 2)'; | |
| }); | |
| button.addEventListener('mouseleave', () => { | |
| button.style.transform = 'translateY(0)'; | |
| button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)'; | |
| }); | |
| buttonContainer.appendChild(button); | |
| const filmContent = film.element.querySelector('[data-testid="content"]'); | |
| // Ajouter le bouton au conteneur du film | |
| filmContent.appendChild(buttonContainer); | |
| }); | |
| console.log(`SensCritique Calendar: ${films.length} bouton(s) ajouté(s)`); | |
| } | |
| // Observer pour détecter les changements dans le DOM (chargement dynamique) | |
| function observeDOM() { | |
| const observer = new MutationObserver((mutations) => { | |
| let shouldUpdate = false; | |
| mutations.forEach(mutation => { | |
| if (mutation.addedNodes.length > 0) { | |
| shouldUpdate = true; | |
| } | |
| }); | |
| if (shouldUpdate) { | |
| setTimeout(addCalendarButtons, 500); | |
| console.log('SensCritique Calendar:zefezfezf Impossible d\'extraire les informations de date de l\'URL'); | |
| } | |
| }); | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| } | |
| // Initialisation | |
| function init() { | |
| // Attendre que la page soit chargée | |
| if (document.readyState === 'loading') { | |
| document. addEventListener('DOMContentLoaded', () => { | |
| setTimeout(addCalendarButtons, 1000); | |
| observeDOM(); | |
| console.log('SensCritique Calendar:zefezfeezfzfzf Impossible d\'extraire les informations de date de l\'URL'); | |
| }); | |
| } else { | |
| setTimeout(addCalendarButtons, 1000); | |
| console.log('SensCritique Calendar:zefezfezfzefezf Impossible d\'extraire les informations de date de l\'URL'); | |
| observeDOM(); | |
| } | |
| // Réexécuter lors des changements de navigation (SPA) | |
| let lastUrl = location.href; | |
| new MutationObserver(() => { | |
| const url = location.href; | |
| if (url !== lastUrl) { | |
| lastUrl = url; | |
| setTimeout(addCalendarButtons, 1000); | |
| } | |
| }).observe(document, { subtree: true, childList: true }); | |
| } | |
| init(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment