Skip to content

Instantly share code, notes, and snippets.

@bsehovac
Last active December 12, 2021 13:00
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save bsehovac/60da2fa1c541e7aa89cdba1beeb9a584 to your computer and use it in GitHub Desktop.
Save bsehovac/60da2fa1c541e7aa89cdba1beeb9a584 to your computer and use it in GitHub Desktop.
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
Copy link

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
Copy link
Author

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
Copy link

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
Copy link

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

@yusufozdennn
Copy link

yusufozdennn 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
Copy link

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
Copy link
Author

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
Copy link

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.

@kyungminjoe
Copy link

Since a few days ago I got this message in the script box. How can I fix it?

Error: the data couldn't be read because it isnt in the correct format.

@usher2005
Copy link

What’s the id for the Los Angeles Rams

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