Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Upcoming Match Scriptable Widget
// Get Team ID from https://www.thesportsdb.com and add it as widget parameter
const TEAM_ID = args.widgetParameter || 133987
const DARK_MODE = true
const widgetSize = config.widgetFamily || 'medium'
const textSize = 9.5
const logoSize = 38
const logoSmallSize = 22
const spacing = { normal: 8, smaller: 6, vs: 5, widget: 10 }
const fetchData = async (url, type = 'loadJSON') => {
const request = new Request(url)
const res = await request[type]()
return res
}
const getTeamData = async id => {
const url = 'https://www.thesportsdb.com/api/v1/json/1/lookupteam.php?id='
const teamUrl = url + id
const data = (await fetchData(teamUrl)).teams[0]
return {
image: await fetchData(`${data.strTeamBadge}/preview`, 'loadImage'),
stadium: data.strStadium
}
}
const getTeamEvents = async () => {
const url = 'https://www.thesportsdb.com/api/v1/json/1/eventsnext.php?id='
const data = await fetchData(url + TEAM_ID)
return data.events
}
const getUpcomingEventData = async event => {
const home = await getTeamData(event.idHomeTeam)
const away = await getTeamData(event.idAwayTeam)
return {
competition: event.strLeague,
homeLogo: home.image,
awayLogo: away.image,
homeTeam: event.strHomeTeam,
awayTeam: event.strAwayTeam,
date: event.strTimestamp,
stadium: home.stadium,
}
}
const getRestEventsData = async events => {
const output = []
for (const event of events) {
const isHomeTeam = event.idHomeTeam ==TEAM_ID
const team = await getTeamData(event[isHomeTeam ? 'idAwayTeam' : 'idHomeTeam'])
output.push({
competition: event.strLeague,
logo: team.image,
team: event[isHomeTeam ? 'strAwayTeam' : 'strHomeTeam'],
date: event.strTimestamp,
stadium: 'stadium',
text: isHomeTeam ? 'vs' : 'at',
})
}
return output
}
const getFormattedDate = (timestamp, useToday = true) => {
const millisPerDay = 24 * 60 * 60 * 1000
const formats = [
"MMM d, yyyy 'at' h:mm a",
"'Tomorrow at' h:mm a",
"'Today at' h:mm a",
]
const date = new Date(timestamp)
const matchDay = (new Date(date)).setHours(0, 0, 0, 0)
const today = (new Date()).setHours(0, 0, 0, 0)
const diff = (matchDay - today) / millisPerDay
const format = useToday ? (diff < 1 ? 2 : diff < 2 ? 1 : 0) : 0
const dateFormatter = new DateFormatter()
dateFormatter.dateFormat = formats[format]
return dateFormatter.string(date)
}
const addText = (el, string, type) => {
const text = el.addText(string)
text.font = type === 'bold' ?
Font.boldSystemFont(textSize * 1.2) :
Font.regularSystemFont(textSize)
text.textColor = new Color(DARK_MODE ? '#ffffff' : '#000000', 1)
text.lineLimit = 1
text.textOpacity = type === 'small' ? 0.5 : 1
text.centerAlignText()
}
const addImage = (el, src, size = logoSize) => {
const image = el.addImage(src)
image.imageSize = new Size(size, size)
}
const addSpacer = (el, type) => {
el.addSpacer(spacing[type])
}
const addStack = (el, type = 'horizontal', centered = false, size) => {
const stack = el.addStack()
if (type === 'vertical') stack.layoutVertically()
else stack.layoutHorizontally()
if (centered) stack.centerAlignContent()
if (size) stack.size = size
return stack
}
const addLogos = (el, homeLogo, awayLogo) => {
const s = addStack(el, 'horizontal', true)
addSpacer(s)
addImage(s, homeLogo)
addSpacer(s, 'vs')
addText(s, 'vs')
addSpacer(s, 'vs')
addImage(s, awayLogo)
addSpacer(s)
}
const initWidget = () => {
const w = new ListWidget()
w.backgroundColor = new Color(DARK_MODE ? '#1B1B1B' : '#FFFFFF', 1)
w.setPadding(
spacing.widget, spacing.widget,
spacing.widget, spacing.widget,
)
return w
}
const addCenteredText = (el, text, type) => {
const s = addStack(el, 'horizontal', true)
addSpacer(s)
addText(s, text, type)
addSpacer(s)
}
const initUpcomingEvent = (el, event) => {
addSpacer(el)
addCenteredText(el, event.competition)
addSpacer(el, 'normal')
addLogos(el, event.homeLogo, event.awayLogo)
addSpacer(el, 'normal')
addCenteredText(el, event.homeTeam.toUpperCase(), 'bold')
addCenteredText(el, event.awayTeam.toUpperCase(), 'bold')
addSpacer(el, 'smaller')
addCenteredText(el, getFormattedDate(event.date))
addCenteredText(el, event.stadium)
addSpacer(el)
}
const initRestEvents = (el, events) => {
events.forEach((data, idx) => {
const hs = addStack(el, 'horizontal', true)
addText(hs, data.text, 'small')
addSpacer(hs, 'vs')
addImage(hs, data.logo, logoSmallSize)
addSpacer(hs, 'vs')
const vs = addStack(hs, 'vertical')
addText(vs, data.team.toUpperCase(), 'bold')
addText(vs, getFormattedDate(data.date, false), 'small')
if (idx < 3) addSpacer(el, 'small')
})
}
const createNextMatchWidget = async () => {
const events = await getTeamEvents()
const widget = initWidget()
if (widgetSize === 'small') {
const upcomingEventData = await getUpcomingEventData(events[0])
initUpcomingEvent(widget, upcomingEventData)
} else if (widgetSize === 'medium') {
const upcomingEventData = await getUpcomingEventData(events[0])
const restEventData = await getRestEventsData(events.slice(1, 5))
const s = addStack(widget, 'horizontal', true)
initUpcomingEvent(addStack(s, 'vertical', true, new Size(130, 135)), upcomingEventData)
addSpacer(s, 'normal')
initRestEvents(addStack(s, 'vertical', true, new Size(160, 135)), restEventData)
}
return widget
}
const widget = await createNextMatchWidget()
Script.setWidget(widget)
Script.complete()
await widget.presentMedium()
@Leibinger015

This comment has been minimized.

Copy link

@Leibinger015 Leibinger015 commented Nov 12, 2020

Kann man den API Code auch so ändern, dass man das aktuelle Ergebnis einer Partie sieht?

Quasi ein Widget mit der Anzeige des letzten Spiels mit Tore Ergebnis und des nächsten Spiels?

@bsehovac

This comment has been minimized.

Copy link
Owner Author

@bsehovac bsehovac commented Nov 12, 2020

Sorry man, I don't understand German. Google Translate translation doesn't make too much sense also, but as I understood you want something like real time result? I don't believe it can be implemented, since widget is refreshed when iOS want's to, we can't force refresh.

@Leibinger015

This comment has been minimized.

Copy link

@Leibinger015 Leibinger015 commented Nov 12, 2020

Sorry!

Is it possible to change the API code to show the current result of a game?

Talking about a widget showing the last game with goals result and the next game?

B40F3577-332C-4CED-AB68-AC00CC27A421

@LemonLimeEsq

This comment has been minimized.

Copy link

@LemonLimeEsq LemonLimeEsq commented Nov 24, 2020

I have two problems, one is that it’s always showing a game playing as ‘Today’ even if it’s not today - and secondly I get the error: ‘Error on line 68:28: Expected Value of type string but got value of type null’
0D906244-6FC8-46EB-BC36-71B53CF4A7F8

@gmaschine

This comment has been minimized.

Copy link

@gmaschine gmaschine commented Dec 3, 2020

Hi,Can i change the widget’s background? Im really bad at that,if you can help me i’ll be grateful and can i change the time zone?

@seanob86

This comment has been minimized.

Copy link

@seanob86 seanob86 commented Feb 11, 2021

Looks like this is broken due to changes in the api.

From the dev section of sportsdb website. Next 5 events by team api requires Patreon 🙁:

Next 5 Events by Team Id
https://www.thesportsdb.com/api/v1/json/1/eventsnext.php?id=133602 Patreon ONLY

@bsehovac

This comment has been minimized.

Copy link
Owner Author

@bsehovac bsehovac commented Feb 11, 2021

Yeah, if someone finds some free api for soccer, please let me know so I can update the widget. But it has to have Red Star Belgrade available if you want to motivate me. 😅

@kjh1998

This comment has been minimized.

Copy link

@kjh1998 kjh1998 commented Feb 12, 2021

I couldn't find the api for sure in the fotmob, but I think there is a widget using it.
-> https://github.com/thejosejorge/futcal-for-scriptable

also
-> https://github.com/bgrnwd/fotmob
I think it's possible to use some of it here, like Api. I wish I could be of help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment