EuroLeague Basketball widget

// Variables used by Scriptable. // These must be at the very top of the file. Do not edit. // icon-color: teal; icon-glyph: magic; // Get Team ID from https://www.thesportsdb.com and add it as widget parameter

const TEAM_ID = args.widgetParameter || 136071 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 backgroundFile= "blackie.JPG"

const fm=FileManager.iCloud() const bgPath = fm.joinPath(fm.documentsDirectory(),backgroundFile)

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.dateEvent+"T"+event.strTime+"Z", 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.dateEvent+"T"+event.strTime+"Z", 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() if (fm.fileExists(bgPath)){ bgImage=fm.readImage(bgPath) w.backgroundImage= bgImage} 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()

/r/Scriptable Thread