Update Arret sur images

This commit is contained in:
Kovid Goyal 2025-01-19 09:03:58 +05:30
parent b9394ff3af
commit ebcfa3dd17
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -1,55 +1,196 @@
from __future__ import unicode_literals #!/usr/bin/env python
# vim:fileencoding=utf-8
__license__ = 'WTFPL' import json
__author__ = '2013, François D. <franek at chicour.net>' from datetime import datetime
__description__ = 'Get some fresh news from Arrêt sur images'
import mechanize
from zoneinfo import ZoneInfo
from calibre import browser
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.web.feeds.recipes import BasicNewsRecipe class ArretSurImages(BasicNewsRecipe):
title = 'Arrêt sur Images'
description = 'Site français d\'analyse des médias'
class Asi(BasicNewsRecipe):
title = 'Arrêt sur images'
__author__ = 'François D. (aka franek)'
description = 'Global news in french from news site "Arrêt sur images"'
oldest_article = 7.0
language = 'fr' language = 'fr'
encoding = 'utf-8'
needs_subscription = True needs_subscription = True
oldest_article = 7
max_articles_per_feed = 100 max_articles_per_feed = 100
simultaneous_downloads = 1
timefmt = '[%a, %d %b %Y %I:%M +0200]'
cover_url = 'http://www.arretsurimages.net/images/header/menu/menu_1.png'
use_embedded_content = False
no_stylesheets = True no_stylesheets = True
remove_javascript = True remove_javascript = True
feeds = [ feeds = [
('vite dit et gratuit', 'http://www.arretsurimages.net/vite-dit.rss'), ('Arrêt sur images', 'https://api.arretsurimages.net/api/public/rss/all-content')
('Toutes les chroniques', 'http://www.arretsurimages.net/chroniques.rss'),
('Contenus et dossiers', 'http://www.arretsurimages.net/dossiers.rss'),
] ]
conversion_options = {'smarten_punctuation': True} def default_cover(self, cover_file):
"""
Crée une couverture personnalisée avec le logo ASI
"""
from qt.core import QColor, QFont, QImage, QPainter, QPen, QRect, Qt
remove_tags = [dict(id='vite-titre'), dict(id='header'), dict(id='wrap-connexion'), dict(id='col_right'), from calibre.gui2 import ensure_app, load_builtin_fonts, pixmap_to_data
dict(name='div', attrs={'class': 'bloc-chroniqueur-2'}), dict(id='footercontainer')] try:
ensure_app()
load_builtin_fonts()
def print_version(self, url): today = datetime.now(ZoneInfo('Europe/Paris'))
return url.replace('contenu.php', 'contenu-imprimable.php') wkd = today.weekday()
french_weekday = {0:'Lundi',1:'Mardi',2:'Mercredi',3:'Jeudi',4:'Vendredi',5:'Samedi',6:'Dimanche'}
french_month = {1:'janvier', 2:'février', 3:'mars', 4:'avril', 5:'mai', 6:'juin',
7:'juillet', 8:'août', 9:'septembre', 10:'octobre', 11:'novembre', 12:'décembre'}
weekday = french_weekday[wkd]
month = french_month[today.month]
date_str = f"{weekday} {today.day} {month} {today.year}"
edition = today.strftime('Édition de %Hh')
img = QImage(1400, 1920, QImage.Format_RGB888)
img.fill(QColor('white'))
# Dessiner la bordure rouge
border_painter = QPainter(img)
border_pen = QPen(QColor('red'))
border_pen.setWidth(120) # Épaisseur de la bordure
border_painter.setPen(border_pen)
border_painter.drawRect(10, 10, img.width()-20, img.height()-20) # Marge de 10 pixels
border_painter.end()
logo_url = 'https://www.arretsurimages.net/assets/img/front/logo-asi-grand.png'
logo_data = browser().open(logo_url).read()
logo = QImage()
logo.loadFromData(logo_data)
logo_width = 800
scaled_logo = logo.scaledToWidth(logo_width, Qt.SmoothTransformation)
x = (img.width() - scaled_logo.width()) // 2
y = (img.height() - scaled_logo.height()) // 2 - 100
p = QPainter(img)
p.drawImage(x, y, scaled_logo)
p.end()
p = QPainter(img)
p.setPen(QPen(QColor('black')))
font = QFont('Liberation Sans', 36)
p.setFont(font)
r = QRect(0, y + scaled_logo.height() + 50, img.width(), 100)
p.drawText(r, Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter, date_str)
font.setItalic(True)
font.setPointSize(32)
p.setFont(font)
r = QRect(0, y + scaled_logo.height() + 150, img.width(), 100)
p.drawText(r, Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter, edition)
p.end()
img_data = pixmap_to_data(img)
cover_file.write(img_data)
cover_file.flush()
return True
except Exception as e:
print(f'Erreur lors de la création de la couverture: {e}')
return False
def get_browser(self): def get_browser(self):
# Need to use robust HTML parser br = BasicNewsRecipe.get_browser(self)
br = BasicNewsRecipe.get_browser(self, use_robust_parser=True) if self.username and self.password:
if self.username is not None and self.password is not None: auth_data = {
br.open('http://www.arretsurimages.net/index.php') 'client_id': '1_1e3dazertyukilygfos7ldzertyuof7pfd',
br.select_form(nr=0) 'client_secret': '2r8yd4a8un0fn45d93acfr3efrgthzdheifhrehihidg4dk5kds7ds23',
br.form.set_all_readonly(False) 'username': self.username,
br['redir'] = 'forum/login.php' 'password': self.password,
br['username'] = self.username 'grant_type': 'password'
br['password'] = self.password }
br.submit() request = mechanize.Request(
'https://api.arretsurimages.net/oauth/v2/token',
data=json.dumps(auth_data).encode('utf-8'),
headers={'Content-Type': 'application/json', 'Accept': 'application/json'}
)
try:
response = br.open(request)
auth_response = json.loads(response.read().decode('utf-8'))
if 'access_token' in auth_response:
br.addheaders += [('Authorization', f'Bearer {auth_response["access_token"]}')]
print('Authentification réussie')
else:
print('Échec de l\'authentification - Vérifiez vos identifiants')
except Exception as e:
print(f'Erreur lors de l\'authentification: {str(e)}')
return br return br
def get_article_url(self, article):
url = article.get('link', article.get('guid'))
if url:
return url.replace('www.arretsurimages.net/', 'api.arretsurimages.net/api/public/contents/')
return None
def preprocess_raw_html(self, raw_html, url):
try:
article_data = json.loads(raw_html)
authors = ', '.join([a.get('name', '') for a in article_data.get('authors', [])])
cover_html = ''
if article_data.get('cover') and article_data['cover'].get('formats', {}).get('article_header'):
cover_slug = article_data['cover']['slug']
cover_url = f'https://api.arretsurimages.net/api/public/media/{cover_slug}/action/show?format=article_header'
cover_html = f'<img src="{cover_url}" alt="{article_data.get("title", "")}">'
return f'''
<html>
<head><title>{article_data.get('title', 'Article sans titre')}</title></head>
<body>
<article>
<h1>{article_data.get('title', 'Article sans titre')}</h1>
<div class="article-meta">
<p>Par {authors or "Auteur inconnu"}</p>
</div>
{cover_html}
<div class="article-content">
<p><strong>{article_data.get('lead', '')}</strong></p>
{article_data.get('content', '')}
</div>
</article>
</body>
</html>
'''
except Exception as e:
print(f'Erreur preprocessing HTML: {str(e)}')
return raw_html
def preprocess_html(self, soup):
try:
for tag in soup.find_all(['asi-html', 'asi-image', 'asi-video']):
if tag.name == 'asi-html' and tag.get('data-html'):
tag.replace_with(soup.new_tag('div', attrs={'class': 'asi-content'}).append(tag['data-html']))
elif tag.name == 'asi-image':
img_data = tag.get('data-image', {})
if img_data:
try:
img_data = json.loads(img_data)
if img_data.get('slug'):
img_url = f'https://api.arretsurimages.net/api/public/media/{img_data["slug"]}/action/show?format=article_body'
img_tag = soup.new_tag('img', src=img_url)
if img_data.get('caption'):
caption_div = soup.new_tag('div', attrs={'class': 'image-caption'})
caption_div.string = img_data['caption']
tag.replace_with(img_tag)
img_tag.insert_after(caption_div)
else:
tag.replace_with(img_tag)
except Exception as e:
print(f'Erreur processing image: {str(e)}')
tag.decompose()
else:
tag.decompose()
return soup
except Exception as e:
print(f'Erreur preprocessing HTML: {str(e)}')
return soup