#!/usr/bin/env python3
"""Resolve Google News RSS article URLs to original media URLs using Playwright."""

import asyncio
from playwright.async_api import async_playwright
import re
import json
import time

# All 50 references: (number, title, source, date, google_news_rss_url)
references = [
    (1, "最後一輪宏福苑聽證會今舉行", "881903.com", "07月15日", "https://news.google.com/rss/articles/CBMiU0FVX3lxTFBNZnFCSzBiNjBkbFF5bUFleVFGcE5FVWwyQ3lRZmpjRWdOLXJhTFY1RHByWXZEdi1xZUg0S2tnWEJIX2o4b0xjVjVnTjcyLTJoVk9B0gFYQVVfeXFMTzdYNkg3WUhSaHRYQW9TS09EZ01QcFVjUlR"),
    (2, "宏福苑聽證會揭各部門災前收大量投訴", "Now新聞", "07月13日", "https://news.google.com/rss/articles/CBMiYkFVX3lxTFBUV19wVGpsZjVpQmE5LVB4ZUN2YXdvYWlubVB6UWhUd043a0xrRi1kNmlNYmJXYVZpS3FiMFdhZXoyQmJEM20zZTRoRVhVbTFhNkNLQXkyeGFmMVo2dDJtVUhR?oc=5"),
    (3, "宏福苑聽證會｜中華發展︰有火警鐘亦難逃生", "Now新聞", "07月15日", "https://news.google.com/rss/articles/CBMiYkFVX3lxTE9idDlaeE1LSlhJWTMxMThpRTJ2NldsUXI5ZWpLcW1MWHItS1hGMFVweEhQUkxhN2JCenN2Q1hYeV9UQTZjbjdJRUlPb2N1aFYyb3RMZmZaLTk2bXBuSTNsaGpR?oc=5"),
    (4, "採訪日誌｜地盤禁煙今日起實施", "Now新聞", "07月16日", "https://news.google.com/rss/articles/CBMiYkFVX3lxTE1yNkt5WWlyMktvNDRxdXI5N1JPUkdKdUZ0d3dzc1FiLUNGYlZqUFowcVVDVEVQMnVWOHBCSVk2M0VJVk5TUkxsckpOUTRXUU9XYWNRY1JkekN6eU5iRTFmZll3?oc=5"),
    (5, "宏福苑聽證會｜居民方總結陳詞批有人卸責", "Now新聞", "07月16日", "https://news.google.com/rss/articles/CBMiYkFVX3lxTFBvS1pOSldYS01EZGhhbUJtaDZuN2d3YzRDU3VXTHpuLVdGLWlPNWVaV1VkN2ZVUHg0cVpNWTlVUDBIdlN0d2FvQk8zRElCTnhZZ09ESGZiVEhjTFN0YkFFRHZ3?oc=5"),
    (6, "宏福苑聽證會｜居民方總結陳詞批有人卸責", "Now新聞", "07月16日", "https://news.google.com/rss/articles/CBMiYkFVX3lxTFA2SjhCdlFOTHVWclF3Zml1QTNDbXNkYXhKRHR4M2pEZF9yb2pqdnJ4d1ZPc0gyRU9COUdzNlR3MXQ1dGxNZVlvQnJyMGptbGh4ZjBxbFNQa2I0QmhQa2VhVWdR?oc=5"),
    (7, "宏福苑聽證會｜孫靖乾︰宏業、鴻毅辜負政府信任", "Now新聞", "07月16日", "https://news.google.com/rss/articles/CBMiYkFVX3lxTE8zSDYtQ1BPVUYyS25KSUpSYVdtYm9jRkh2RXhHaVNYT08xRnlZNkMyY09TZGFmOWVVaGtlN0VjbXFSYW5JMm13dDlTcGk5OTdYaFJxOXhwaXNGYTNqeHV2T3RB?oc=5"),
    (8, "宏福苑聽證會各方總結", "RTHK News", "07月15日", "https://news.google.com/rss/articles/CBMib0FVX3lxTE9SVG5kT0tjSWtGcC11NlBCUm5ZM3VOdTVQeDAzZ1R6aG1BTTU2VlVxWThMOU1HU1lGS2VfWm05NTk1bkdmTmJ5X3V6MlhVZ2owWEN3YkFPc2hnV2lyY2JoN3BHemVuUGRjbm1zdl95MA?oc=5"),
    (9, "宏福苑聽證會繼續總結陳詞", "RTHK News", "07月16日", "https://news.google.com/rss/articles/CBMib0FVX3lxTE94WjRoRm4zbzJIMmF5ZnltMHliT1o0UjM1ZFkxbVB4LUx0d05vby1xUE5SRDEzLWExd1JPQ09xWm5ZN3ljS21leGVlUU9JT0ZFMVB2UEotbjRCRUsyalg1UjhpLVB5NFh1b1Bjai1CRQ?oc=5"),
    (10, "宏福苑聽證會揭示圍標問題", "Singtaousa", "07月15日", "https://news.google.com/rss/articles/CBMijgFBVV95cUxPNXpHbWVEN0YxUVdoSG52RUN3emotRnluTlZ2QTkzWEpaa3ZReHBxVjFfMlNFaUNONkJPMl9BSXhxRkJtY2FqalFGWkRYLWg2N3FuQUw4d0pxSUxWSlJnYkUyc2pMUHZqcTVRV3pGYkNvX1g0Ym9"),
    (11, "宏福苑大火聽證會政府總結陳詞", "Singtaousa", "07月16日", "https://news.google.com/rss/articles/CBMiogFBVV95cUxPdEM2VXJycmc2MHBVMnBLZDFmYzNtQTNDUlo0SWU1dlZtRkYxU1JneS1wTERpZElIY1ZxVkFzYWZFcFZLczRpZGxZclhzQmc5ZGxCc2xzREZ5XzNqZjFvNDlfenlrM21ReEJkRnV3cWRSMWtpVGZ"),
    (12, "宏福苑聽證會政府總結陳詞", "Singtaousa", "07月16日", "https://news.google.com/rss/articles/CBMipAFBVV95cUxOSllVS2hFOF9LY1BwR2piM2hySUJBMVdaWGVkMjdpLXNHSlRWV3Q4bDNmZjQtbFhWRjBaLTIzaXJiLVlkNW5iWllva2gycy0zNUVtUHprMFpBXzcxbXVwWFVXdVQ1OEhYNVNtQ2diVkYwVTJuUml"),
    (13, "宏福苑第六輪聽證會月中舉行", "Yahoo", "07月02日", "https://news.google.com/rss/articles/CBMi9AJBVV95cUxNcE9VemdYQ1c5dWJ5Y3VhRUQwR2E3SHRXV2pQdmtsQmRwQ3ZGdGNfQWMtZVZxc1RNVWRzbGh4bkFpNDdfMFFLbUVqTC1hWTBCSjhObmFrWS05RnVjNHFBOGhOdnRJT29jSlIxc0dRVmsyWnRCcW9"),
    (14, "宏福苑聽證會揭各部門災前收大量投訴", "Yahoo", "07月13日", "https://news.google.com/rss/articles/CBMivgNBVV95cUxOSnJDRXRTY1BaaTlvcFo4RTU3SXFTVEF5VkhlZ3FsTV9wT0RRSlJTUktaWmVNZlliTnJZREJfT25oYmYwRlROOWVfX0RHY2o2NjZFcWt4Qy0xSnhIMV9EalBZQVBBOW5KQjJldVN5QmE2OFJzbkp"),
    (15, "宏福苑聽證會｜競委會：有圍標由三合會領導", "Yahoo", "07月15日", "https://news.google.com/rss/articles/CBMiiARBVV95cUxQUm05R2xzUWo0azRKNjdDMGRVb1BseE9ySEI5dWhqeGN2WE9rR19jZ1czaWtLeUhJNHAwUUUxZ0JZUV9nQ0t2MUtaWWNKYVBqU2ZGYjg3eVl0X0dLcEMzS2gyLW83N3lNLXhVZ2FkZnFGR0tPVF8"),
    (16, "宏福苑聽證會｜置邦：大維修期間沒任何監督角色", "Yahoo", "07月15日", "https://news.google.com/rss/articles/CBMizANBVV95cUxOMElmVVBtaDM4MmJfaTZRbmlBci1vVFRCWnVrTkVySy04MDVxSU1GcWExX0JVc1BxTS11cnRFYmE4OGhlXzFTOERmV3IwLW51OWhqLWdmd3JaLThVVzQ4cVpTS2NOSUkxbFFSS0xfVzBXd2cxOEx"),
    (17, "晨早新聞重點｜宏福苑聽證會", "Yahoo", "07月16日", "https://news.google.com/rss/articles/CBMi9ARBVV95cUxPSXlBYnFJS2NOSW05RFA5cXBVVVdwSWdmQlBoS3dZUTd2ZTJKTmVvODY1c2V6VkNWcTJMV25JOTUwbmZRc3hRWl9SVVJjNlRFaGh5aVRwcTZ2MndvY2Z1aUFxTUZmNU1JQUVYbUoxWXZUNXRiNlN"),
    (18, "宏福苑聽證會｜居民方總結陳詞批有人卸責", "Yahoo", "07月16日", "https://news.google.com/rss/articles/CBMi1wNBVV95cUxOZXlpNWZVcmM2Rm1tVHBTczVHOXZTQ1kybFZRcmloOV9rU2JaQmo1N0hfYUZrUUo2WUNvMzZENWphRmFNbjBBQ2V1XzZrYlJmUUp5ZXBuZHVQVl9tVUdadnZHQldHMkV1R3EtNGd5Y0tZM1NJM1I"),
    (19, "宏福苑聽證會｜政府指承建商須負首要責任", "Yahoo", "07月16日", "https://news.google.com/rss/articles/CBMivgNBVV95cUxNODcyTzJ6VHZxQmNvOFFiSVF0c2cyWE1ESFFDQ0pYbTc3ZjVtaGY2VllUbmRWRkFlaGY1a29weTVFX2ZUcm5yX1RtT0dVR0VMTVJ6MjBuM3lEaGFVZ3dRRVAxR2hCb0VDWWFoSC1WNGxZQlJCSU9"),
    (20, "即日焦點｜宏福苑聽證會總結陳詞", "Yahoo", "07月16日", "https://news.google.com/rss/articles/CBMiwwRBVV95cUxNbi1GdTNHbGlOWFV2Qm5adVMzck1wMDV6OVFfV2c2Qm1kTWlTaVhBWVFVeFdRUmtqRUhNbm1GSi1mREZFSkt6ckxlTWRpYUlYUUdpNTFRdmY4eGpXS3lKRVRpNkZrSWFoT25JRkh2YzZOSUc0TlA"),
    (21, "聽證會｜宏福苑居民指政府有不可推卸責任", "am730", "07月16日", "https://news.google.com/rss/articles/CBMi8gNBVV95cUxQa2NRcllLb3Z1S2pUZUVzQkc4cUJ6RzZlNW9NQ1p4dk5YN2taM3Nka2NFSmRqdkZYaW1hTmhSMkhOa2pDald6SDhMWHVPU2VaMGZHZzFtN2J5V0NIN2RPMldLS3JvZGR6aF9CazlONzA1bkdZT1o"),
    (22, "香港宏福苑聽證會政府總結陳詞", "hkcna.hk", "07月16日", "https://news.google.com/rss/articles/CBMiZkFVX3lxTE5lRldKS0Z4U29MQzZzYnNlZ3R6d2FPTVU4TXFiT2ZqSEZqY3lmQnNzTnozRGhNZDExQkswRVNRUlRZXzlsdGJIYWRXRW5ScC1RTFEyenpRVE5ZWmU2Nm1KN2dDTzA3UQ?oc=5"),
    (23, "宏福苑大火獨委會總結陳詞", "on.cc東網", "07月17日", "https://news.google.com/rss/articles/CBMiiwFBVV95cUxNcEE5VDRTcTRxbHkxR0RCQ093TFBRM1c0RjFWcEE4TlJ3cndLT3RmbjJVSXRmZEpDOG1qazFQaEtZT1hqTXhQUUFSdjJ5anFUSFctWlVfdHp1NHd1bGt3NzlKYnItUnRnQU9XQlp5MFZkclcxZFV"),
    (24, "宏福苑聽證會｜最後一輪聽證會今舉行", "singtao.ca", "07月15日", "https://news.google.com/rss/articles/CBMijAFBVV95cUxPaTFVa1VtN2JaMGhZME1XdTRncmQ1MGZCLXVpWEI2RXhyNXRiNEcyMDFsZWlRQ1FmWVZ4RG13ZTUzZ0dDMzNLNWhiYWlMb3VrbnkyVWpQUFhqbWV1SnpwdFFZRU1MTERSQk10YkdMaDRGeExUY0U"),
    (25, "宏福苑聽證會｜政府代表總結陳詞", "singtao.ca", "07月16日", "https://news.google.com/rss/articles/CBMivgRBVV95cUxNdXZNVVZhRDVYYWstZzMwX1FvNEdwdFF3YklPZDRWWW01ZDJzTWo1eWJ1cG95WDFpOUg5MmVCM0x0U3JqSEUwcEg1RHFRRzFndlo5MVdoM2sxRDUwS09hQUh5OTZEV2xqVzRua096YW1hXzlLSE5"),
    (26, "宏福苑聽證會｜黃碧嬌工程前期扮演一定角色", "singtao.ca", "07月16日", "https://news.google.com/rss/articles/CBMi7wRBVV95cUxQS1FpalpGOEFhMV9URC1xdlhUUHFjZjhHMmJZQjJyWjlVRWlxWTZGa3Q3LWNsVmw1dlNmZVpSanROOTlKOGkwTVB4QXpDUF9yU2IyS25RVnRzelJWcy1JS3EtYjNyNDk3bnZ0X0F4VE1QWXdseF9"),
    (27, "宏福苑聽證會｜物管置邦斥宏泰消防董事供詞信口雌黃", "信報網站", "07月15日", "https://news.google.com/rss/articles/CBMi_wJBVV95cUxPcXRLUTR3TnFFUFJrU0lTLUpVVEttOWdGTWFMNGl5eGp3MEdEMU52Mjl0eVhDcEZ2NnFMcTBqV3dKSXpkREZOVlpFRG9nN21kV2U4eEpOUHFaWVhRODNXZXBROWw2RF9BS3NTS08wSkRqeVJPcmV"),
    (28, "宏福苑聽證會｜政府代表:專業人士及承建商蓄意違法", "信報網站", "07月16日", "https://news.google.com/rss/articles/CBMiXkFVX3lxTE9QT0ROSUxvS2V6eHZwaFc4SEtmcFNRcDhIbzY3cEI0NVUwTU1wdzVVVGtKWDhXWTltOWxkcmozeGZIOHZLb3F3Q2FsVmhkLWxiVUhPSVRDbTlUVnFRcXc?oc=5"),
    (29, "宏福苑聽證會｜最後一輪最後一場", "信報網站", "07月17日", "https://news.google.com/rss/articles/CBMi9wJBVV95cUxPeXdOSGxZelhwN194aXllT2oteUZOLXd4NjR6VzJVWDljUXlPV0UtY2tEMlp6eGtEQUNWTHh2Z0ZnSXVyLWg5a3kwUnFPQ1JUYUFlY0F3TlY0VFZIaWIza05oZ3JLeElUdHpZSjhzT0pMbEJyUUx"),
    (30, "宏福苑火災聽證會/政府大律師", "大公文匯網", "07月16日", "https://news.google.com/rss/articles/CBMidEFVX3lxTE8yd0dYMmhGRWNHZHpYNVdHVTVIMDgxYjkxWTJaeUJaTy1rSlExTWZXdTJaVFNObk4xSmRjVllJV2RYMUdQZFc3RzhkVUxPZ3poNUZwS3g0TW9wWHJrX1NhVDJZTlNPYlhhZ1pOUW4xb2dwRWMx?oc"),
    (31, "強化監管/議員倡重新檢視行業指引", "大公文匯網", "07月16日", "https://news.google.com/rss/articles/CBMidEFVX3lxTE9za3ZLekctc3hHVjJieXZYTHBKdFVGXzRvaEdPSVVhbWVLN0FXT291eGNMOG9VMUZoUFNYZHR6QWw5OWgzdUR0TXBLV3pETjB1bl9LSUxLc1hpSVdTVXBseGduUHQ5WFB1UXplWmRqa2h2V1pQ?oc"),
    (32, "宏福苑五級火聽證會｜政府方陳詞", "庭刊", "07月16日", "https://news.google.com/rss/articles/CBMixwJBVV95cUxObmtELVY0a1RZdlR0YWFGWDd5bVFYUXhLMGx0UE82dGR2NVhfLUJXYXZ6dGtUYURyQWktT2o2cFVxa2FTbjJlUzRhUUY0Mk0xOEhGZGJ5dklQdkhuR1FUeXk5dDlCYVB1LUtOQ2drWkhINFFrczk"),
    (33, "宏福苑五級火聽證會｜政府方結案陳詞", "庭刊", "07月16日", "https://news.google.com/rss/articles/CBMixwJBVV95cUxPcUdiVzBPVEVnNDZjUkpUaW9TakZ4NXNmRW9IQWJFdFQwVFRZcGJYY3I1OUVZbFFoeUNHbUc4RU1sd0xoWm5yVzRENVM5NXpWNS1jNWx2MHVMUmpmRkM4Zzl3SjloYWZienM5ZDA2NExacjJIazh"),
    (34, "宏福苑火災聽證會｜物管置邦", "明報新聞網", "07月15日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxPNEtHcXh5UElvZ2VfUUo2VEl2bllXQ1BSUEdON0c2blBCa3hLM29fY1JvZDdYLWNEU08xNFZIWWt4TlpsY0RyVVd4UWIzR25QYlhQcTBPaUhnLUZyMElXQ2dPVFdqZHhQWndMUlVDb0FpdzJ6ZGl"),
    (35, "宏福苑火災聽證會｜政府代表稱監管責任", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxPSUhvTnBwbnhwaTZFVF9XamhOMmRGTXduX050QTZrOFViV1B3ZWlfY0J0S0pueGplejFSWm95NVhyVllRRUpnS19rS2pGYmpLbFFvUmY3d2xXOHBMUVZSTE5Ib2N0YjFoRWtUWmk1RlAwZVJvMWI"),
    (36, "宏福苑火災聽證會｜政府：六大因素促成火災", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxOck51Sm1GSURiclBXeHYyTndac3gxS2RMUzI5T2NabXJaQWx5ZFdEZW9GZm5pZXdZaFhxVU5zY1NOczFVM2V0TlVzTkc3Y25UNzUzWlFCUHI0clYzcXR2cVVNNjFNcHZrM0hwNnNidGhBbjBQcEJ"),
    (37, "宏福苑火災聽證會｜政府稱識別5個制度弱點", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxOeDYtM3hBVF90SWZUbThMSFdJdjN3eE1YVkZ6Q09kNjRHZTN0aDdxNmlWS0hwSVZ5YVEwQ2tteV9RVk1VemlzZHBEczZyTGZaeHY3TXB4c2lFZ1BTdHVHLVVwYWZoQzdUR0tMcUkyODR5UUZBY2R"),
    (38, "宏福苑居民：一句「對不起」及認責非奢侈", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxPRVZiSk82SDB4em0xdTR0d1RCS3NqVHV0NzE3TTNXUlFSUGRidTcyWkphV3EyaGI1b3Q2RGlia0VjaWRKeVJsR1RlUEpua1Q1V2tFV0xWN3lSSmJSQ0Z2UDRIeVc2b1lTNndKcUtaN1Z5bDlQM1R"),
    (39, "宏福苑火災聽證會｜居民代表律師", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxQQjNVU21iVXFOTmp3c3dIVDFyeXJ1UFJVSmQxSkpwNGU0TVphNTkyN2tpejQzcG5MYms4M08wa1Fnb0RwOXhYTGxZai00WGlLemM2OFk2Y2ZTSzRIVVZhSzg2Z1dSdWR3c2dOTDFiYVM1dmVvUG9"),
    (40, "【持續更新】宏福苑火災聽證會｜政府指六大因素引發火災", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMi_wRBVV95cUxQc0dOVjBOdVNDU3o1V3VYbTk3Nzk2MEY3LUJFaFB5OUhZODZQMmFNcXlfczZGalB0QXQtRUdTdDBtcVVNNE91aTVXMFp6NU5MN3pQVVlpaXR3cGtxeDA1SFZPTHJtd1ZZYVJzUUR6VjkxRmVlVUV"),
    (41, "旁聽居民批淡化責任", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxPb3hpSDNzMnVwczRleHVkODNSOVhDTDBIZDBSLXZUNmwyeFVmMXhRSE4wMHctbGFManBHQ3BTNzNkVXFldlhPT2hEa3lEcEdEeWNXOS1rdXdyWncwUERVY2lwa0xiWEw0am9SY28zcHktMnNvb0s"),
    (42, "鄧國權黃碧嬌無作供 居民陳辭點名", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMixAJBVV95cUxPTWk1ZXBlUEI5NzhZVkpmNElsRE43R0xid1ViRmgyUUxHenN3VDVORDNyYmMyc2llU2hZSVF5enRQLUFaWDJ1c2xGcS1DbjBEVTlpUy1uYW5pYTQ1ZlF6UHBERjMtRUoxNzdIekRnUVVueGJVOTR"),
    (43, "宏福苑火災聽證會｜有居民認為政府部門對火災有責任", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxQSXZsem11Vm5xRGU3NDFuYm5Ra0NBUndXNnJSOXNhNzRCOTBOMXFqV2dBSXZFby1yeFFGZ0hmczRLZjRKZnRWUXpsbzBCN2pXal9CaEREbEhIVkg2d0ZxbTBncl9HSElPUFRSNjVpUHNMS1FOSmR"),
    (44, "宏福苑火災聽證會｜政府：火警規模前所未見", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMiswFBVV95cUxOcldOS2w2azVtWDgxRWQxcTh2TzE5dE9LaWdFUTJ3MVItdkxwOXo1YXoxdmozQXBjNGs1bkNVWnQzLVUzakRsNGNTbFJNZGFTck5OelI2SVRrZy1xWGRqeGdEYlBJVDVHaXlLd3V6UWFhdjEzcnV"),
    (45, "識別5「系統性弱點」", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMixgJBVV95cUxORUZ6RDNqLVhCVGc5Y3Itb2otcXotX2NXeUk4QWFLeDlSVnk3ekhXNUxGaXFmVVdFcDRFWVp1MGJWOUE0Z3BjN3RJcUVZaTBpN1drWmRabzB0MlYxZXMzRHhNYnFhNVR3ampGd1FNanZ2WnQxSDQ"),
    (46, "居民總結：環環失誤釀禍", "明報新聞網", "07月16日", "https://news.google.com/rss/articles/CBMinwFBVV95cUxQZnp4QXZvdllMZklJWkRhaW4waTN4R3NiV2t5QVItWndVNm9mQlRseEZfMWlncVdLYnhvTHB5amdHeHkxdUtiMzJrX2JPblFPWm5NRUtGZ1BSYUthbjdtSHJUOFkxOEtldWtkMExTenZPa1NQWV9"),
    (47, "宏福苑聽證會第六輪周三起舉行3場", "星島頭條", "07月13日", "https://news.google.com/rss/articles/CBMizgNBVV95cUxOU1VLaWZINHpEa09nYWtneGJ1LUhhRkctdm1sQ1REaXFhbmQzVTVwWHNzaW1VOHJ2ZnU3clNjYWtMbHZWSlcxQnZneGJrYmhkeF9ySVo1YnhoMF9rSHItNnlySXRfazBaclNSZXJhSlZEaVF1R2Q"),
    (48, "宏福苑聽證會｜政府承認監管制度存五大弱點", "星島頭條", "07月16日", "https://news.google.com/rss/articles/CBMi7wNBVV95cUxPSl9vM0RrUEdoa2FhRUtrVW0tcEtyUk9wbHQ0dExMb24xUmRnaGtLVDJWOFQyUE83bGI3SUIyTXI2YzBDYkNfRUNrdE94aUNWMHdkVEE0R3hfWlRrZHh0bF92TG9QLU1PNjBOaVJVN0FuZ3lyQ3N"),
    (49, "宏福苑聽證會｜何偉豪留在宏泰閣嘗試協助疏散", "星島頭條", "07月16日", "https://news.google.com/rss/articles/CBMi7ANBVV95cUxPV0p3b0d6VFlLRjJ5N1JrV3I0Q3p6cVJlWnBKbXN2RVh4d1J5OHplYmp1MGl2dF9hRERfcDlBRlJ5QndfdlVKN1RNN19HYWd2OHVyR2FiMjVfMnFKd0ZfcFBiYlpZcXdKRGdF"),
    (50, "宏福苑大火最終一輪聽證會", "星島頭條", "07月17日", "https://news.google.com/rss/articles/CBMitgNBVV95cUxQMkVvNEVXN2xYMVF4c0ZxNWNUS3hQdUdaTnN0a3RLdXNlVnpBTmR2VTV3LW9uQjE3Z2hVOTRlZjgtUTd6LW9oMGJlMUt5d3BjNmp3X0dBRnJNb0ZPcG9KWGpYOW9iS19nZ2tuQ0d6b2RjY0RzVg"),
]


def extract_article_id(rss_url):
    """Extract the article ID from a Google News RSS URL."""
    # RSS URL format: https://news.google.com/rss/articles/{ARTICLE_ID}?oc=5
    match = re.search(r'/rss/articles/([^?]+)', rss_url)
    if match:
        return match.group(1)
    return None


async def resolve_all_articles(references):
    """Resolve all Google News article URLs to original media URLs."""
    results = []
    
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True, args=['--no-sandbox', '--disable-dev-shm-usage'])
        context = await browser.new_context(
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            locale='zh-HK'
        )
        
        for i, (num, title, source, date, rss_url) in enumerate(references):
            article_id = extract_article_id(rss_url)
            if not article_id:
                results.append({
                    'num': num, 'title': title, 'source': source, 'date': date,
                    'original_url': None, 'error': 'Could not extract article ID',
                    'google_news_url': rss_url
                })
                continue
            
            # Construct the non-RSS Google News URL
            gn_url = f'https://news.google.com/articles/{article_id}?hl=zh-HK&gl=HK&ceid=HK:zh-Hant'
            
            page = await context.new_page()
            try:
                response = await page.goto(gn_url, timeout=15000)
                await page.wait_for_timeout(2000)
                
                final_url = page.url
                page_title = await page.title()
                
                # Check if we were redirected to the original article
                if 'news.google.com' not in final_url:
                    # Successfully redirected to original article
                    results.append({
                        'num': num, 'title': title, 'source': source, 'date': date,
                        'original_url': final_url,
                        'page_title': page_title,
                        'google_news_url': rss_url
                    })
                else:
                    # Still on Google News - try to find the original article link
                    links = await page.eval_on_selector_all('a[href]', '''
                        elements => elements.map(e => e.href)
                    ''')
                    # Find external links (non-Google)
                    external = [l for l in links if l and 
                               'google.com' not in l and 
                               'gstatic.com' not in l and
                               'googleapis.com' not in l and
                               'googleusercontent.com' not in l and
                               len(l) > 20]
                    
                    if external:
                        results.append({
                            'num': num, 'title': title, 'source': source, 'date': date,
                            'original_url': external[0],
                            'page_title': page_title,
                            'google_news_url': rss_url,
                            'note': 'Found via external link'
                        })
                    else:
                        # Try to get the URL from the page content
                        content = await page.content()
                        # Look for data attributes that might contain the URL
                        url_match = re.search(r'data-n-au="([^"]+)"', content)
                        if url_match:
                            results.append({
                                'num': num, 'title': title, 'source': source, 'date': date,
                                'original_url': url_match.group(1),
                                'page_title': page_title,
                                'google_news_url': rss_url,
                                'note': 'Found via data attribute'
                            })
                        else:
                            results.append({
                                'num': num, 'title': title, 'source': source, 'date': date,
                                'original_url': None,
                                'error': f'Still on Google News: {final_url}',
                                'page_title': page_title,
                                'google_news_url': rss_url
                            })
                
                print(f"[{i+1}/50] #{num} {source}: {'OK' if results[-1].get('original_url') else 'FAILED'} - {results[-1].get('original_url', results[-1].get('error', ''))[:100]}")
                
            except Exception as e:
                results.append({
                    'num': num, 'title': title, 'source': source, 'date': date,
                    'original_url': None, 'error': str(e),
                    'google_news_url': rss_url
                })
                print(f"[{i+1}/50] #{num} {source}: ERROR - {str(e)[:100]}")
            
            finally:
                await page.close()
            
            # Small delay to avoid rate limiting
            await asyncio.sleep(0.5)
        
        await browser.close()
    
    return results


async def main():
    print(f"Resolving {len(references)} Google News RSS URLs...")
    results = await resolve_all_articles(references)
    
    # Save results to JSON
    with open('/root/.openclaw/workspace/resolved_urls.json', 'w', encoding='utf-8') as f:
        json.dump(results, f, ensure_ascii=False, indent=2)
    
    # Print summary
    success = sum(1 for r in results if r.get('original_url'))
    failed = sum(1 for r in results if not r.get('original_url'))
    print(f"\n=== Summary ===")
    print(f"Total: {len(results)}")
    print(f"Success: {success}")
    print(f"Failed: {failed}")
    print(f"\nResults saved to resolved_urls.json")
    
    # Print all results
    print(f"\n=== All Results ===")
    for r in results:
        url = r.get('original_url', 'N/A')
        error = r.get('error', '')
        print(f"#{r['num']:2d} [{r['source']:8s}] {r['title'][:30]:30s} -> {url[:100] if url else 'FAILED: ' + error[:80]}")

asyncio.run(main())
