@@ -307,7 +307,6 @@ def get_date(x):
307307 return ''
308308
309309 new_films .sort (key = get_date , reverse = True )
310-
311310 recent_updates = new_films [:limit ]
312311
313312 os .makedirs (os .path .dirname (output_json_path ), exist_ok = True )
@@ -316,9 +315,123 @@ def get_date(x):
316315
317316 print (f"Saved { len (recent_updates )} recent updates to { output_json_path } " )
318317
318+ # GENERATE RSS
319+ generate_rss_feed (recent_updates )
320+
319321 except Exception as e :
320322 print (f"Error generating recent updates: { e } " )
321323
324+ def generate_rss_feed (films , output_path = "static/rss.xml" ):
325+ """Generate RSS feed from recent films list."""
326+ from html import escape
327+ import base64
328+
329+ print ("Generating static RSS feed..." )
330+
331+ rss_items = []
332+
333+ for film in films :
334+ title = escape (f"CBFC Watch: { film .get ('movie_name' , 'Unknown' )} ({ film .get ('year' , '' )} ) - { film .get ('language' , '' )} " )
335+ link = f"https://www.cbmcwatch.com/film/{ film .get ('slug' , '' )} "
336+
337+ try :
338+ date_obj = datetime .strptime (film .get ('cert_date' , '' ), '%Y-%m-%d' )
339+ pub_date = date_obj .strftime ("%a, %d %b %Y 00:00:00 GMT" )
340+ except :
341+ pub_date = ""
342+
343+ # Description Construction
344+ desc_html = ""
345+
346+ # Poster
347+ if film .get ('imdb_poster_url' ):
348+ desc_html += f'<img src="{ escape (film .get ("imdb_poster_url" ))} " alt="{ escape (film .get ("movie_name" , "" ))} " style="width: 150px; height: 225px; object-fit: cover;" /><br/>'
349+
350+ # Rating & IMDb
351+ if film .get ('imdb_rating' ) or film .get ('rating' ):
352+ meta_parts = []
353+ if film .get ('rating' ): meta_parts .append (f"Certificate: { film .get ('rating' )} " )
354+ if film .get ('imdb_rating' ): meta_parts .append (f"IMDb: { film .get ('imdb_rating' )} /10" )
355+ desc_html += f'<p><strong>Rating:</strong> { escape (" | " .join (meta_parts ))} </p>'
356+
357+ # Overview
358+ if film .get ('imdb_overview' ):
359+ desc_html += f'<p>{ escape (film .get ("imdb_overview" ))} </p>'
360+
361+ # Credits
362+ credits = []
363+ if film .get ('imdb_directors' ):
364+ d = ", " .join (film .get ('imdb_directors' ).split ('|' )[:3 ])
365+ credits .append (f"<strong>Director:</strong> { escape (d )} " )
366+ if film .get ('imdb_actors' ):
367+ a = ", " .join (film .get ('imdb_actors' ).split ('|' )[:4 ])
368+ credits .append (f"<strong>Cast:</strong> { escape (a )} " )
369+ if credits :
370+ desc_html += f'<p>{ " | " .join (credits )} </p>'
371+
372+ desc_html += "<hr/>"
373+
374+ # Modifications
375+ mod_desc = film .get ('ai_cleaned_description' ) or film .get ('description' ) or 'No description'
376+ cut_no = film .get ('cut_no' ) or '1'
377+
378+ desc_html += "<h3><strong>Modifications</strong></h3><ul>"
379+ desc_html += f"<li><strong>#{ cut_no } :</strong> { escape (mod_desc )} </li>"
380+ desc_html += "</ul>"
381+
382+ # Footer Links
383+ links = []
384+ links .append (f'<a href="{ link } ">View on CBFC Watch</a>' )
385+ if film .get ('imdb_id' ):
386+ imdb_clean = film .get ('imdb_id' , '' ).split ('.' )[0 ].zfill (7 )
387+ links .append (f'<a href="https://www.imdb.com/title/tt{ imdb_clean } /">IMDb</a>' )
388+
389+ if film .get ('id' ):
390+ links .append (f'<a href="https://www.ecinepramaan.gov.in/cbfc/?a=Certificate_Detail&i={ escape (film .get ("id" ))} ">E-Cinepramaan</a>' )
391+
392+ if film .get ('cbfc_file_no' ):
393+ try :
394+ encoded = base64 .b64encode (film .get ('cbfc_file_no' ).encode ('utf-8' )).decode ('utf-8' )
395+ links .append (f'<a href="https://www.cbfcindia.gov.in/cbfcAdmin/search-result.php?recid={ encoded } ">CBFC Listing</a>' )
396+ except :
397+ pass
398+
399+ desc_html += f'<p>{ " | " .join (links )} </p>'
400+
401+ if film .get ('id' ):
402+ desc_html += f'<p><em>For original modifications, refer to <a href="https://www.ecinepramaan.gov.in/cbfc/?a=Certificate_Detail&i={ escape (film .get ("id" ))} ">E-Cinepramaan</a></em></p>'
403+
404+ rss_items .append (f""" <item>
405+ <title>{ title } </title>
406+ <link>{ link } </link>
407+ <pubDate>{ pub_date } </pubDate>
408+ <guid isPermaLink="false">{ film .get ('slug' , 'unknown' )} </guid>
409+ <description><![CDATA[{ desc_html } ]]></description>
410+ <media:content url="{ escape (film .get ('imdb_poster_url' , '' ))} " medium="image" />
411+ </item>""" )
412+
413+ rss_xml = f"""<?xml version="1.0" encoding="UTF-8" ?>
414+ <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:dc="http://purl.org/dc/elements/1.1/">
415+ <channel>
416+ <title>CBFC Watch - Recent Certifications</title>
417+ <link>https://www.cbmcwatch.com</link>
418+ <description>Latest film certifications and censorship records from the Central Board of Film Certification, India.</description>
419+ <language>en</language>
420+ <lastBuildDate>{ datetime .utcnow ().strftime ("%a, %d %b %Y %H:%M:%S GMT" )} </lastBuildDate>
421+ <atom:link href="https://www.cbmcwatch.com/rss.xml" rel="self" type="application/rss+xml" />
422+ """
423+ rss_xml += "\n " .join (rss_items )
424+ rss_xml += """
425+ </channel>
426+ </rss>"""
427+
428+ try :
429+ with open (output_path , 'w' , encoding = 'utf-8' ) as f :
430+ f .write (rss_xml )
431+ print (f"Saved static RSS feed to { output_path } " )
432+ except Exception as e :
433+ print (f"Error saving RSS feed: { e } " )
434+
322435def fetch_remote_data (output_path = "src/lib/data/data.csv" , limit = 20 ):
323436 """Fetch latest data from remote source by cloning the repo."""
324437 os .makedirs (os .path .dirname (output_path ), exist_ok = True )
0 commit comments