I made a thing that might help today (1 Viewer)

shmmeee

Well-Known Member
Got ChatGPT to code me a widget for my phone that shows the top five thread titles on the CCFC forum. So in theory I don’t have to come here and get sucked in and can just watch for a thread about a new signing. It works as a piece of software it does not work as a way to stop my coming on SBT too much. Thought I’d share.

iOS you need to download an app called Scriptable then create a new script, past the below in, save it with a name, and then add the scriptable widget to your Home Screen and choose run script and select the one you made.

Here’s what it looks like:
IMG_4855.png

Here’s the script:




Code:
// SkyBlueTalk — CCFC Top Threads (polished)
// Medium/Small widget. Auto dark/light, club sky-blue gradient.
// Taps: header → forum, each row → thread.

// ── CONFIG ─────────────────────────────────────────────────────────────────────
const FEED_URL = "https://www.skybluestalk.co.uk/forums/coventry-city-general-chat.7/index.rss";
const MAX_ITEMS = 5;             // keep 3–6 for Medium, 2–4 for Small
const TITLE_LINE_LIMIT = 1;      // 1 = tidy, 2 = roomier
const SHOW_REL_TIME = true;      // show “· 1h” after title
const TRIM_PREFIXES = [
  /^match\s*thread[:\-\s]*/i,
  /^pre[-\s]?match[:\-\s]*/i,
  /^post[-\s]?match[:\-\s]*/i,
  /^transfer(s)?[:\-\s]*/i,
  /^\[\s*rumou?r\s*\]\s*/i
];
// Colors
const SKY = Color.dynamic(new Color("#69b9ff"), new Color("#2b86d1"));
const DEEP = Color.dynamic(new Color("#1a6db3"), new Color("#154e80"));
const TEXT = Color.dynamic(Color.black(), Color.white());
const SUBTLE = Color.dynamic(new Color("#334155"), new Color("#b0c4d9"));
// ───────────────────────────────────────────────────────────────────────────────

async function fetchRSS(url){
  const req = new Request(url);
  req.headers = { "User-Agent": "ScriptableWidget/1.1 (+iOS)" };
  return await req.loadString();
}

function parseRSS(xml){
  const items = [];
  const blocks = xml.match(/<item>[\s\S]*?<\/item>/g) || [];
  for (let i=0; i<Math.min(blocks.length, MAX_ITEMS); i++){
    const b = blocks[i];
    const t = textOf(b, "title");
    items.push({
      title: prettifyTitle(t),
      link: textOf(b, "link"),
      date: new Date(textOf(b, "pubDate") || Date.now())
    });
  }
  return items;
}

function textOf(block, tag){
  const m = new RegExp(`<${tag}>([\\s\\S]*?)<\\/${tag}>`, "i").exec(block);
  return (m ? m[1] : "").replace(/<!\[CDATA\[|\]\]>/g,"").trim();
}

function prettifyTitle(t){
  let s = t.replace(/\s+/g," ").trim();
  for (const rx of TRIM_PREFIXES) s = s.replace(rx,"");
  // collapse bracketed prefixes like [Tickets], (H), etc. at start
  s = s.replace(/^(\[.*?\]|\(.*?\))\s+/g,"");
  return s;
}

function timeAgo(d){
  const secs = Math.max(1, (Date.now() - d.getTime())/1000);
  if (secs < 60) return `${Math.floor(secs)}s`;
  const mins = secs/60;
  if (mins < 60) return `${Math.floor(mins)}m`;
  const hrs = mins/60;
  if (hrs < 24) return `${Math.floor(hrs)}h`;
  const days = hrs/24;
  return `${Math.floor(days)}d`;
}

function header(w){
  const h = w.addStack();
  h.layoutHorizontally();
  h.centerAlignContent();
  h.url = "https://www.skybluestalk.co.uk/forums/coventry-city-general-chat.7/";
  const badge = SFSymbol.named("soccerball");
  const img = h.addImage(badge.image);
  img.imageSize = new Size(14,14);
  img.tintColor = TEXT;
  h.addSpacer(6);
  const t = h.addText("SkyBlueTalk — CCFC");
  t.font = Font.boldSystemFont(12);
  t.textColor = TEXT;
  h.addSpacer();
  const refresh = h.addText(new Date().toLocaleTimeString([], {hour:"2-digit", minute:"2-digit"}));
  refresh.font = Font.systemFont(10);
  refresh.textColor = SUBTLE;
}

function row(w, item){
  const s = w.addStack();
  s.layoutHorizontally();
  s.url = item.link;

  // bullet
  const dot = s.addText("•");
  dot.font = Font.boldSystemFont(13);
  dot.textColor = TEXT;
  s.addSpacer(6);

  // title
  const t = s.addText(item.title);
  t.font = Font.systemFont(13);
  t.textColor = TEXT;
  t.lineLimit = TITLE_LINE_LIMIT;

  if (SHOW_REL_TIME){
    s.addSpacer(6);
    const ago = s.addText(`· ${timeAgo(item.date)}`);
    ago.font = Font.systemFont(11);
    ago.textColor = SUBTLE;
  }
}

function makeWidget(items){
  const w = new ListWidget();
  const grad = new LinearGradient();
  grad.colors = [SKY, DEEP];
  grad.locations = [0, 1];
  grad.startPoint = new Point(0, 0);
  grad.endPoint = new Point(1, 1);
  w.backgroundGradient = grad;
  w.setPadding(10, 12, 10, 12);

  header(w);
  w.addSpacer(6);
  items.forEach((it, idx) => {
    row(w, it);
    if (idx < items.length-1) w.addSpacer(4);
  });

  return w;
}

async function run(){
  try{
    const xml = await fetchRSS(FEED_URL);
    const items = parseRSS(xml);
    const widget = makeWidget(items);
    if (config.runsInWidget) Script.setWidget(widget);
    else await widget.presentMedium();
  } catch (e){
    const w = new ListWidget();
    w.addText("SkyBlueTalk — error").font = Font.boldSystemFont(12);
    w.addText(String(e)).font = Font.systemFont(10);
    Script.setWidget(w);
  }
  Script.complete();
}
await run();
 

Grendel

Well-Known Member
When I read the title I thought it was a commitment from you to not make any more idiotic posts
 

Nick

Administrator
Can you not just use an RSS reader app? It saves trying to scrape and you get the clean xml
 

djr8369

Well-Known Member
ChatGPT actually managed that without so much debugging you basically had to write it yourself?
 

shmmeee

Well-Known Member
Can you not just use an RSS reader app? It saves trying to scrape and you get the clean xml

Ah maybe I can. Will have a look. The troubles with vibe coding.
 

shmmeee

Well-Known Member
ChatGPT actually managed that without so much debugging you basically had to write it yourself?

One shot ten seconds work. But as Nick points out not the best solution. So still very ChatGPT.
 

shmmeee

Well-Known Member
Should be able to get the RSS link for a certain forum 😁

If it works though, it works 🤣

I didn’t even realise SBT had an rss feed. I didn’t even realise rss feeds were still a thing.
 

Captain Dart

Well-Known Member

Nick

Administrator
You can get RSS reader apps and then just add the URL to get the latest posts into it
 

Noble

Well-Known Member
Quite liked the intent here and set up the RSS feed for notifications, just for some absolute whopper to post that we’d signed Hughes
 

Users who are viewing this thread

Top