Skip to content

Instantly share code, notes, and snippets.

@eopo
Last active June 8, 2024 15:45
Show Gist options
  • Save eopo/9344584035f487db0e229d655bdb39c4 to your computer and use it in GitHub Desktop.
Save eopo/9344584035f487db0e229d655bdb39c4 to your computer and use it in GitHub Desktop.
iOS widget powered by the Scriptable app that shows the current capacity of FitnessFirst Gyms
/**
* Script for scriptable to get the current capacity of FitnessFirst Gyms
*/
let gymId = 'essen1'
let param = args.widgetParameter
if (param != null && param.length > 0) {
gymId = param
}
const currentGymCapacity = await fetchGymCapacity(gymId)
const storeInfo = await fetchGymInfo(gymId)
const gymName = await fetchGymInfo(gymId)
const widget = new ListWidget()
await createWidget()
if (!config.runsInWidget) {
await widget.presentSmall()
}
Script.setWidget(widget)
Script.complete()
//Create the widget
async function createWidget() {
const headlineText = widget.addText("🏋️ Capacity")
headlineText.font = Font.mediumRoundedSystemFont(19)
widget.addSpacer()
const widgetStack = widget.addStack()
widgetStack.layoutVertically()
widgetStack.bottomAlignContent()
const capacityText = widgetStack.addText(currentGymCapacity.toString() + "%")
capacityText.font = Font.mediumRoundedSystemFont(50)
if (currentGymCapacity < 20) {
capacityText.textColor = new Color("#33cc33")
} else if (currentGymCapacity < 30){
capacityText.textColor = new Color("#ff9900")
}else{
capacityText.textColor = new Color("#ff3300")
}
widgetStack.addSpacer(1)
const gymNameText = widgetStack.addText(gymName)
gymNameText.font = Font.regularSystemFont(12)
}
//Fetches the current capacity of the John Reed gym
async function fetchGymCapacity(id) {
const url = 'https://www.fitnessfirst.de/club/api/checkins/' + id
const req = new Request(url)
const result = await req.loadJSON()
return Math.round(result.data.check_ins*100/ result.data.allowed_people)
}
//Fetches the name of the gym
async function fetchGymInfo(id) {
const url = 'https://www.fitnessfirst.de/api/v1/node/club_page?include=field_features,field_opening_times&filter[status][value]=1&page[limit]=40&sort=title'
const req = new Request(url)
const apiResult = await req.loadJSON()
for (var i in apiResult.data){
if(apiResult.data[i].attributes.field_easy_solution_club_id == id)
{
return apiResult.data[i].attributes.title;
}
}
return 'Your Gym'
}
@eopo
Copy link
Author

eopo commented Oct 23, 2020

Fork of https://gist.github.com/masselmello/6d4f4c533b98b2550ee23a7a5e6c6cff

image

How to use:

  1. You need to have Scriptable on your iOS 14 device and open it
  2. Tap on the plus in the upper right corner
  3. Tap on "Untitled Script" and give the script a name, for example "Gym Capacity"
  4. Copy the source code from above and paste it in the blank field
  5. Save it.
  6. Go to your home screen and enter wiggle mode. Then tap on the plus in the upper left corner.
  7. Select Scriptable from the promoted widgets, the app list or search for scriptable.
  8. Select your widget size.
  9. Tap on "Add widget"
  10. Tap on the newly added widget.
  11. Select the John Reed script. On "When Interacting", you can select "Run Script", but it'll work just fine with "Open App"
  12. Paste your studio ID as parameter. You can see it in the table below.
    image
  13. Finished! 😍
Studio ID
Berlin - Friedrichshain - Ladies berlin207
Berlin - Gendarmenmarkt berlin12
Berlin - Pankow - Ladies berlin209
Berlin - Prenzlauer Berg berlin2
Berlin - Steglitz berlin3
Berlin - Steglitz - Im Schloss - Ladies berlin206
Berlin - Steglitz - SSC berlin203
Berlin - Wilmersdorf berlin10
Berlin - Zehlendorfer Welle berlin11
Bielefeld bielefeld2
Bonn bonn1
Darmstadt darmstadt1
Dresden dresden2
Düsseldorf - Derendorf duesseldorf5
Düsseldorf - Im Lighthouse duesseldorf6
Düsseldorf - Schadow Arkaden duesseldorf3
Essen - Kettwig essen1
Frankfurt - Eckenheim frankfurt3
Frankfurt - Eschenheimer Turm frankfurt7
Frankfurt - Konstablerwache frankfurt8
Frankfurt - MyZeil frankfurt10
Frankfurt - Opernplatz frankfurt12
Frankfurt - Ostend frankfurt11
Frankfurt - Sachsenhausen - Ladies frankfurt4
Frankfurt - Westend frankfurt9
Göttingen goettingen1
Hamburg - Altona hamburg7
Hamburg - Eppendorf hamburg3
Hamburg - Jungfernstieg hamburg6
Hamburg - Niendorf hamburg4
Hamburg - Rödingsmarkt hamburg1
Hamburg - St. Georg hamburg2
Hamburg - Stephansplatz hamburg8
Hamburg - Wandsbek hamburg5
Kaiserslautern kaiserslautern1
Kassel kassel1
Köln - Bayenthal koeln3
Köln - Breite Straße koeln6
Köln - Ehrenfeld koeln2
Köln - Schildergasse koeln1

@Brototype
Copy link

Brototype commented Apr 26, 2022

Thank you!

One studio to add to your list:

Studio ID
München Haidhausen muenchen6

I also adjusted the page[limit]=40 to 100 for my studio to be part of the result set.

Another nice thing i figured out. If you have the Fitness First App you can set the widget interaction to "URL" and the URL to com.netpulse.fitnessfirst:// that will open the App when you tap on the widget

@chafrei
Copy link

chafrei commented Jun 8, 2024

Thank you.
It seems like the API has changed in 2023, according to this post.
I don't know JavaScript, but I managed to fix the widget for my case.
The gymId can now be discovered by following the procedure from the post linked above:

Visit your club’s website (e.g. https://www.fitnessfirst.de/clubs/hamburg-mitte-jungfernstieg 6)
Open Developer Console (F12) and search for data-club below block-clubcheckinsblock. You’ll need to copy that number from data-club (e.g. 1376532610)
Alternatively, reload the page with open network tab and you should see a request with a number (e.g. 1376532610).

GymID for München Haidhausen: 1363429860
I also needed to change the function that accesses the JSON file (thanks to ChatGPT).

My entire code looks like this (you need to change gymId and the gymNameText for your studio):

/**
 * Script for scriptable to get the current capacity of FitnessFirst Gyms 
 */
let gymId = '1363429860'
let param = args.widgetParameter
if (param != null && param.length > 0) {
    gymId = param
}

const currentGymCapacity = await fetchGymCapacity(gymId)
//const storeInfo = await fetchGymInfo(gymId)
const widget = new ListWidget()
await createWidget()

if (!config.runsInWidget) {
    await widget.presentSmall()
  }

Script.setWidget(widget)
Script.complete()

//Create the widget
async function createWidget() {

  const headlineText = widget.addText("🏋️ Capacity")
  headlineText.font = Font.mediumRoundedSystemFont(19)
  
  widget.addSpacer()
  
  const widgetStack = widget.addStack()
  widgetStack.layoutVertically()
  widgetStack.bottomAlignContent()
  	
  const capacityText = widgetStack.addText(currentGymCapacity.toString() + "%")
  
  capacityText.font = Font.mediumRoundedSystemFont(50)
  
  if (currentGymCapacity < 30) {
      capacityText.textColor = new Color("#33cc33") //green
  } else if (currentGymCapacity < 50){
      capacityText.textColor = new Color("#ff9900")//orange
  }else{
      capacityText.textColor = new Color("#ff3300")//red
  }
  
  widgetStack.addSpacer(1)
        
  const gymNameText = widgetStack.addText("FF Haidhausen")
  gymNameText.font = Font.regularSystemFont(12)

}

async function fetchGymCapacity(id) {
  const url = 'https://www.fitnessfirst.de/club/api/checkins/' + id;
  const req = new Request(url);
  const result = await req.loadJSON();

  // Find the current time slot and get its percentage
  const currentTimeSlot = result.data.items.find(item => item.isCurrent);
  return currentTimeSlot ? currentTimeSlot.percentage : null;
}

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