diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-10-17 18:01:11 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-10-17 18:01:11 -0400 |
| commit | 6ca4d7a6b6c896cfcba0b3dfe02bf135b5c8ead7 (patch) | |
| tree | e35928104292b91693489bd3fb1952b70b4916ce | |
| parent | 464e3ff178545c21de8e2d64f8c8cd7dec4d5384 (diff) | |
pke-at: first-pass parse planning center json
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | config.mk | 3 | ||||
| -rw-r--r-- | data/plan-items.json | 1 | ||||
| -rw-r--r-- | data/service-types.json | 1 | ||||
| -rw-r--r-- | data/upcoming-plans.json | 1 | ||||
| -rw-r--r-- | src/pke-at-common.cpp | 127 | ||||
| -rw-r--r-- | src/pke-at-common.hpp | 5 | ||||
| -rw-r--r-- | src/pke-at-data-interface-types.hpp | 68 | ||||
| -rw-r--r-- | src/pke-at-data-interface.hpp | 38 | ||||
| -rw-r--r-- | src/pke-at-data-parser.cpp | 218 | ||||
| -rw-r--r-- | src/pke-at-data-parser.hpp | 11 | ||||
| -rw-r--r-- | src/pke-at-data-stub.cpp | 61 | ||||
| -rw-r--r-- | src/pke-at-data-stub.hpp | 15 | ||||
| -rw-r--r-- | src/pke-at-setlist-types.hpp | 27 | ||||
| -rw-r--r-- | tests/pke-at-test-data-parser.cpp | 241 | ||||
| -rw-r--r-- | tests/pke-at-test-data-parser.h | 8 | ||||
| -rw-r--r-- | tests/pke-at-test-main.cpp | 8 |
18 files changed, 840 insertions, 4 deletions
@@ -1 +1,2 @@ src/sql/*sql.h +data/*json.h @@ -44,6 +44,9 @@ FILES_BIN = \ src/sql/song_delete.sql \ src/sql/song_get.sql \ src/sql/song_upsert.sql \ + data/service-types.json \ + data/upcoming-plans.json \ + data/plan-items.json \ FILES_BIN_SAFE = $(subst -,_,$(subst .,_,$(FILES_BIN))) FILES_BIN_H = $(FILES_BIN_SAFE:%=%.h) @@ -77,6 +80,7 @@ options: prepare .WAIT @echo "CXX = $(CXX)" obj/pke-at-storage-sql.o : $(FILES_BIN_GCH) +obj/pke-at-data-stub.o : $(FILES_BIN_GCH) obj/%.o : src/%.c | prepare $(cc-command) obj/%.o : src/%.cpp | prepare @@ -91,12 +95,18 @@ bin/pke-at: obj/level-init.o bin/pke-at: obj/level-main.o bin/pke-at: obj/main.o bin/pke-at: obj/pke-at-common.o +bin/pke-at: obj/pke-at-data-stub.o +bin/pke-at: obj/pke-at-data-parser.o bin/pke-at: obj/pke-at-settings.o bin/pke-at: obj/pke-at-storage-sql.o bin/pke-at: obj/pke-at.o $(CXX) -v -std=c++23 $(BUILD_MODE_FLAGS) $(INCS) -Wl,--whole-archive $^ $(LDFLAGS) -Wl,--no-whole-archive $(CXXFLAGS) -o $@ bin/pke-at-test: ## Builds the pke-at-test executable +bin/pke-at-test: obj/pke-at-common.o +bin/pke-at-test: obj/pke-at-data-parser.o +bin/pke-at-test: obj/pke-at-settings.o +bin/pke-at-test: obj/pke-at-test-data-parser.o bin/pke-at-test: obj/pke-at-test-dummy.o bin/pke-at-test: obj/pke-at-test-main.o $(CXX) -v -std=c++23 $(BUILD_MODE_FLAGS) $(INCS) -Wl,--whole-archive $^ $(LDFLAGS) -Wl,--no-whole-archive $(CXXFLAGS) -o $@ @@ -21,7 +21,8 @@ GLSLC = /usr/bin/glslc # libspa-0.2 \ USED_STATIC_LIBS = pke \ - sqlite3 + sqlite3 \ + nlohmann_json \ USED_LIBS = diff --git a/data/plan-items.json b/data/plan-items.json new file mode 100644 index 0000000..9e7bf10 --- /dev/null +++ b/data/plan-items.json @@ -0,0 +1 @@ +{"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items?include=song%2Carrangement%2Ckey"},"data":[{"type":"Item","id":"1116826595","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":null,"html_details":null,"item_type":"item","key_name":null,"length":600,"sequence":1,"service_position":"pre","title":"PreService Slides","updated_at":"2025-08-26T16:06:19Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826595"}},{"type":"Item","id":"1116826597","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":null,"html_details":null,"item_type":"item","key_name":null,"length":300,"sequence":2,"service_position":"pre","title":"Go Live","updated_at":"2025-08-26T16:06:19Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826597"}},{"type":"Item","id":"1116826600","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Project 216 recap video\n","html_details":null,"item_type":"item","key_name":null,"length":60,"sequence":3,"service_position":"during","title":"Welcome video","updated_at":"2025-10-16T14:43:16Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826600"}},{"type":"Item","id":"1116826607","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Orlando Eagles VIDEO","html_details":null,"item_type":"item","key_name":null,"length":180,"sequence":4,"service_position":"during","title":"Ministry Opportunities ","updated_at":"2025-10-16T14:42:46Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826607"}},{"type":"Item","id":"1130476699","attributes":{"created_at":"2025-10-10T01:41:03Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Play videos in order then Eric prays over families all at once","html_details":null,"item_type":"item","key_name":null,"length":300,"sequence":5,"service_position":"during","title":"Child dedication","updated_at":"2025-10-10T01:43:56Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1130476699"}},{"type":"Item","id":"1130476794","attributes":{"created_at":"2025-10-10T01:42:39Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Play video and baptism one at a time\nSamantha Best 1st service\nBill Munger, Kay Munger, Alyssa Miller 2nd service","html_details":null,"item_type":"item","key_name":null,"length":720,"sequence":6,"service_position":"during","title":"Baptism","updated_at":"2025-10-14T15:11:13Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1130476794"}},{"type":"Item","id":"1116826609","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Steph","html_details":null,"item_type":"song","key_name":"G","length":270,"sequence":7,"service_position":"during","title":"This Is Our God","updated_at":"2025-10-13T21:37:15Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"links":{"related":"https://api.planningcenteronline.com/services/v2/songs/24030215"},"data":{"type":"Song","id":"24030215"}},"arrangement":{"links":{"related":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826609/arrangement"},"data":{"type":"Arrangement","id":"27793425"}},"key":{"links":{"related":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826609/key"},"data":{"type":"Key","id":"44596256"}},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826609"}},{"type":"Item","id":"1116826612","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Rocky","html_details":null,"item_type":"song","key_name":"G","length":240,"sequence":8,"service_position":"during","title":"Egypt","updated_at":"2025-10-13T21:37:19Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"links":{"related":"https://api.planningcenteronline.com/services/v2/songs/22058189"},"data":{"type":"Song","id":"22058189"}},"arrangement":{"links":{"related":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826612/arrangement"},"data":{"type":"Arrangement","id":"25398725"}},"key":{"links":{"related":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826612/key"},"data":{"type":"Key","id":"45863343"}},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826612"}},{"type":"Item","id":"1116826614","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Rocky","html_details":null,"item_type":"song","key_name":"G","length":243,"sequence":9,"service_position":"during","title":"Good Grace","updated_at":"2025-10-13T21:37:24Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"links":{"related":"https://api.planningcenteronline.com/services/v2/songs/18743841"},"data":{"type":"Song","id":"18743841"}},"arrangement":{"links":{"related":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826614/arrangement"},"data":{"type":"Arrangement","id":"21448360"}},"key":{"links":{"related":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826614/key"},"data":{"type":"Key","id":"29304181"}},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826614"}},{"type":"Item","id":"1116826618","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Steph","html_details":null,"item_type":"item","key_name":null,"length":60,"sequence":10,"service_position":"during","title":"Worship Leader Prayer","updated_at":"2025-10-10T01:47:11Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826618"}},{"type":"Item","id":"1116826621","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":null,"html_details":null,"item_type":"item","key_name":null,"length":60,"sequence":11,"service_position":"during","title":"***Bumper Video***","updated_at":"2025-08-26T16:06:19Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826621"}},{"type":"Item","id":"1116826623","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Timmons\n","html_details":null,"item_type":"item","key_name":null,"length":1800,"sequence":12,"service_position":"during","title":"Teaching","updated_at":"2025-10-10T01:40:38Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826623"}},{"type":"Item","id":"1131208437","attributes":{"created_at":"2025-10-13T21:36:28Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":"Steph\n","html_details":null,"item_type":"song","key_name":"D","length":240,"sequence":13,"service_position":"during","title":"My Heart Is Yours","updated_at":"2025-10-13T21:36:51Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"links":{"related":"https://api.planningcenteronline.com/services/v2/songs/12327928"},"data":{"type":"Song","id":"12327928"}},"arrangement":{"links":{"related":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1131208437/arrangement"},"data":{"type":"Arrangement","id":"13840808"}},"key":{"links":{"related":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1131208437/key"},"data":{"type":"Key","id":"21251195"}},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1131208437"}},{"type":"Item","id":"1116826625","attributes":{"created_at":"2025-08-26T16:06:19Z","custom_arrangement_sequence":null,"custom_arrangement_sequence_full":null,"custom_arrangement_sequence_short":null,"description":null,"html_details":null,"item_type":"item","key_name":null,"length":60,"sequence":14,"service_position":"during","title":"Closing Remarks","updated_at":"2025-08-26T16:06:19Z"},"relationships":{"plan":{"data":{"type":"Plan","id":"82934314"}},"song":{"data":null},"arrangement":{"data":null},"key":{"data":null},"selected_layout":{"data":null},"selected_background":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826625"}}],"included":[{"type":"Song","id":"24030215","attributes":{"admin":null,"author":"Brandon Lake, Pat Barrett, Phil Wickham, and Steven Furtick","ccli_number":7211413,"copyright":" Brandon Lake Music (Admin by Essential Music Publishing), Maverick City Publishing Worldwide (Admin by Essential Music Publishing), Music by Elevation Worship Publishing (Admin. by Essential Music Publishing LLC), Phil Wickham Music (Fair Trade Music Publishing [c/o Essential Music Publishing LLC]), Simply Global Songs (Fair Trade Music Publishing [c/o Essential Music Publishing LLC]), and Remaining portion is unaffiliated","created_at":"2023-03-28T01:28:56Z","hidden":false,"last_scheduled_at":"2025-10-19T11:00:00Z","last_scheduled_short_dates":"Oct 19, 2025","notes":null,"themes":"Faithfulness, Power, Praise, Redemption, Salvation","title":"This Is Our God","updated_at":"2023-03-28T01:33:20Z"},"links":{"self":"https://api.planningcenteronline.com/services/v2/songs/24030215"}},{"type":"Arrangement","id":"27793425","attributes":{"archived_at":null,"bpm":null,"chord_chart":"Verse 1\n\nRemember those walls that we called sin and shame\nThey were like prisons that we couldn’t escape\nBut He came and He died and He rose\nThose walls are rubble now\nRemember those giants we called death and grave\nThey were like mountains that stood in our way\nBut He came and He died and He rose\nThose giants are dead now\n\nChorus 1\n\nThis is our God this is who He is\nHe loves us\nThis is our God this is what He does\nHe saves us\nHe bore the cross beat the grave\nLet heaven and earth proclaim\nThis is our God King Jesus\n\nVerse 2\n\nRemember that fear that took our breath away\nFaith so weak that we could barely pray\nBut He heard every word every whisper\nNow those altars in the wilderness\nTell the story of His faithfulness\nNever once did He fail and He never will\n\nMisc 1\n\n(Bridge)\nWho pulled me out of that pit\nHe did He did\nWho paid for all of our sin\nNobody but Jesus\n\nMisc 2\n\n(Bridge)\nWho rescued me from that grave\nYahweh Yahweh\nWho gets the glory and praise\nNobody but Jesus (Him)\n\nMisc 3\n\n(Ending)\nHe bore the cross beat the grave\nLet heaven and earth proclaim\nThis is our God King Jesus","chord_chart_chord_color":0,"chord_chart_columns":1,"chord_chart_font":"Courier","chord_chart_font_size":12,"chord_chart_key":"C","created_at":"2023-03-28T01:28:56Z","has_chord_chart":true,"has_chords":false,"length":240,"lyrics":"Verse 1\n\nRemember those walls that we called sin and shame\nThey were like prisons that we couldn’t escape\nBut He came and He died and He rose\nThose walls are rubble now\nRemember those giants we called death and grave\nThey were like mountains that stood in our way\nBut He came and He died and He rose\nThose giants are dead now\n\nChorus 1\n\nThis is our God this is who He is\nHe loves us\nThis is our God this is what He does\nHe saves us\nHe bore the cross beat the grave\nLet heaven and earth proclaim\nThis is our God King Jesus\n\nVerse 2\n\nRemember that fear that took our breath away\nFaith so weak that we could barely pray\nBut He heard every word every whisper\nNow those altars in the wilderness\nTell the story of His faithfulness\nNever once did He fail and He never will\n\nMisc 1\n\n(Bridge)\nWho pulled me out of that pit\nHe did He did\nWho paid for all of our sin\nNobody but Jesus\n\nMisc 2\n\n(Bridge)\nWho rescued me from that grave\nYahweh Yahweh\nWho gets the glory and praise\nNobody but Jesus (Him)\n\nMisc 3\n\n(Ending)\nHe bore the cross beat the grave\nLet heaven and earth proclaim\nThis is our God King Jesus","lyrics_enabled":true,"meter":null,"name":"Phil Wickham","notes":null,"number_chart_enabled":false,"numeral_chart_enabled":false,"print_margin":"0.5in","print_orientation":"Portrait","print_page_size":"Letter","sequence":[],"sequence_full":[],"sequence_short":[],"updated_at":"2024-11-17T00:41:39Z"},"relationships":{"updated_by":{"data":{"type":"Person","id":"3825437"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"song":{"data":{"type":"Song","id":"24030215"}}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826609/arrangement"}},{"type":"Key","id":"44596256","attributes":{"alternate_keys":[],"created_at":"2024-01-04T16:21:23Z","ending_key":null,"ending_minor":false,"name":null,"starting_key":"G","starting_minor":false,"updated_at":"2025-03-16T11:08:27Z"},"relationships":{"arrangement":{"data":{"type":"Arrangement","id":"27793425"}}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826609/key"}},{"type":"Song","id":"22058189","attributes":{"admin":null,"author":"Brian Johnson, Cory Asbury, Ethan Hulse, Lee Cummings, and Phil Wickham","ccli_number":7133348,"copyright":"2019 Bethel Music Publishing and Remaining portion is unaffiliated","created_at":"2022-03-11T15:24:06Z","hidden":false,"last_scheduled_at":"2025-11-23T11:00:00Z","last_scheduled_short_dates":"Nov 23, 2025","notes":null,"themes":null,"title":"Egypt","updated_at":"2022-03-11T15:24:59Z"},"links":{"self":"https://api.planningcenteronline.com/services/v2/songs/22058189"}},{"type":"Arrangement","id":"25398725","attributes":{"archived_at":null,"bpm":75,"chord_chart":null,"chord_chart_chord_color":0,"chord_chart_columns":1,"chord_chart_font":"Courier","chord_chart_font_size":12,"chord_chart_key":null,"created_at":"2022-03-11T15:24:06Z","has_chord_chart":false,"has_chords":false,"length":240,"lyrics":null,"lyrics_enabled":true,"meter":"4/4","name":"Cory Asbury ","notes":null,"number_chart_enabled":false,"numeral_chart_enabled":false,"print_margin":"0.5in","print_orientation":"Portrait","print_page_size":"Letter","sequence":[],"sequence_full":[],"sequence_short":[],"updated_at":"2025-06-27T18:11:59Z"},"relationships":{"updated_by":{"data":{"type":"Person","id":"3825437"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"song":{"data":{"type":"Song","id":"22058189"}}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826612/arrangement"}},{"type":"Key","id":"45863343","attributes":{"alternate_keys":[],"created_at":"2024-04-03T12:51:44Z","ending_key":null,"ending_minor":false,"name":null,"starting_key":"G","starting_minor":false,"updated_at":"2024-04-03T13:12:26Z"},"relationships":{"arrangement":{"data":{"type":"Arrangement","id":"25398725"}}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826612/key"}},{"type":"Song","id":"18743841","attributes":{"admin":null,"author":"Joel Houston","ccli_number":7122177,"copyright":"2018 Hillsong Music Publishing (Admin. by Capitol CMG Publishing)","created_at":"2020-02-05T21:16:25Z","hidden":false,"last_scheduled_at":"2025-10-19T11:00:00Z","last_scheduled_short_dates":"Oct 19, 2025","notes":null,"themes":null,"title":"Good Grace","updated_at":"2020-02-05T21:16:26Z"},"links":{"self":"https://api.planningcenteronline.com/services/v2/songs/18743841"}},{"type":"Arrangement","id":"21448360","attributes":{"archived_at":null,"bpm":73,"chord_chart":"Verse 1\n\nPeople come together\nStrange as neighbours our blood is one\nChildren of generations\nOf every nation of Kingdom come\n\nChorus 1\n\nDon't let your heart be troubled\nHold your head up high don't fear no evil\nFix your eyes on this one truth\nGod is madly in love with you\nTake courage hold on be strong\nRemember where our help comes from\n\nVerse 2\n\nJesus our redemption\nOur salvation is in His blood\nJesus Light of heaven\nFriend forever His Kingdom come\n\nMisc 1\n\n(Bridge)\nSwing wide all you heavens\nLet the praise go up as the walls come down\nAll creation everything with breath repeat the sound\nAll His children clean hands pure hearts\nGood grace good God His Name is Jesus","chord_chart_chord_color":0,"chord_chart_columns":1,"chord_chart_font":"Courier","chord_chart_font_size":12,"chord_chart_key":"G","created_at":"2020-02-05T21:16:25Z","has_chord_chart":true,"has_chords":false,"length":243,"lyrics":"Verse 1\n\nPeople come together\nStrange as neighbours our blood is one\nChildren of generations\nOf every nation of Kingdom come\n\nChorus 1\n\nDon't let your heart be troubled\nHold your head up high don't fear no evil\nFix your eyes on this one truth\nGod is madly in love with you\nTake courage hold on be strong\nRemember where our help comes from\n\nVerse 2\n\nJesus our redemption\nOur salvation is in His blood\nJesus Light of heaven\nFriend forever His Kingdom come\n\nMisc 1\n\n(Bridge)\nSwing wide all you heavens\nLet the praise go up as the walls come down\nAll creation everything with breath repeat the sound\nAll His children clean hands pure hearts\nGood grace good God His Name is Jesus","lyrics_enabled":true,"meter":"4/4","name":"Hillsong United","notes":null,"number_chart_enabled":false,"numeral_chart_enabled":false,"print_margin":"0.5in","print_orientation":"Portrait","print_page_size":"Letter","sequence":["Verse 1","Chorus","Refrain","Verse 2","Chorus","Refrain","Bridge","Bridge","Bridge","Verse 2","Ending"],"sequence_full":[{"label":"Verse","number":"1"},{"label":"Chorus","number":"1"},{"label":"Refrain","number":"1"},{"label":"Verse","number":"2"},{"label":"Chorus","number":"1"},{"label":"Refrain","number":"1"},{"label":"Bridge","number":"1"},{"label":"Bridge","number":"1"},{"label":"Bridge","number":"1"},{"label":"Verse","number":"2"},{"label":"Ending","number":"1"}],"sequence_short":["V1","C","Rf","V2","C","Rf","B×3","V2","E"],"updated_at":"2025-10-10T18:00:08Z"},"relationships":{"updated_by":{"data":{"type":"Person","id":"95051396"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"song":{"data":{"type":"Song","id":"18743841"}}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826614/arrangement"}},{"type":"Key","id":"29304181","attributes":{"alternate_keys":[],"created_at":"2020-02-05T21:16:36Z","ending_key":null,"ending_minor":false,"name":null,"starting_key":"G","starting_minor":false,"updated_at":"2021-08-31T21:25:21Z"},"relationships":{"arrangement":{"data":{"type":"Arrangement","id":"21448360"}}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1116826614/key"}},{"type":"Song","id":"12327928","attributes":{"admin":"EMI Christian Music Publishing","author":"Brett Younker and Daniel Carson","ccli_number":7017788,"copyright":"2014 Open Hands Music (Admin. by Sony/ATV Sounds LLC)","created_at":"2016-06-08T18:29:53Z","hidden":false,"last_scheduled_at":"2025-10-19T11:00:00Z","last_scheduled_short_dates":"Oct 19, 2025","notes":null,"themes":null,"title":"My Heart Is Yours","updated_at":"2021-10-28T13:51:03Z"},"links":{"self":"https://api.planningcenteronline.com/services/v2/songs/12327928"}},{"type":"Arrangement","id":"13840808","attributes":{"archived_at":null,"bpm":null,"chord_chart":"Verse 1\n\nI give you my life\nI give You my trust Jesus\nAnd You are my God\nAnd You are enough Jesus\n\nChorus 1\n\nMy heart is Yours my heart is Yours\nTake it all take it all\nMy life in Your hands\nMy heart is Yours (Lord) my heart is Yours\nTake it all take it all\nMy life in Your hands\n\nVerse 2\n\nI lay down my life\nI take up my cross Jesus\nFor You are my God\nWhatever the cost Jesus\nO Jesus\n\nChorus 2\n\nAnd all to Jesus I surrender\nAll to You I freely give\nOh I will ever love and trust You\nIn Your presence I will live\n\nMisc 1\n\n(Interlude)\nI just want to be with You\nI just want to be with You\nLord we just want to be with You\nLord we just want to be with You\nOh wherever You are and wherever You're going\nLord wherever You are and wherever You're going\nOh take us with You oh take us with You\nOh wherever You're going I just want to be with You","chord_chart_chord_color":0,"chord_chart_columns":1,"chord_chart_font":"Courier","chord_chart_font_size":12,"chord_chart_key":"A","created_at":"2016-06-08T18:29:53Z","has_chord_chart":true,"has_chords":false,"length":240,"lyrics":"Verse 1\n\nI give you my life\nI give You my trust Jesus\nAnd You are my God\nAnd You are enough Jesus\n\nChorus 1\n\nMy heart is Yours my heart is Yours\nTake it all take it all\nMy life in Your hands\nMy heart is Yours (Lord) my heart is Yours\nTake it all take it all\nMy life in Your hands\n\nVerse 2\n\nI lay down my life\nI take up my cross Jesus\nFor You are my God\nWhatever the cost Jesus\nO Jesus\n\nChorus 2\n\nAnd all to Jesus I surrender\nAll to You I freely give\nOh I will ever love and trust You\nIn Your presence I will live\n\nMisc 1\n\n(Interlude)\nI just want to be with You\nI just want to be with You\nLord we just want to be with You\nLord we just want to be with You\nOh wherever You are and wherever You're going\nLord wherever You are and wherever You're going\nOh take us with You oh take us with You\nOh wherever You're going I just want to be with You","lyrics_enabled":true,"meter":null,"name":"Default Arrangement","notes":null,"number_chart_enabled":false,"numeral_chart_enabled":false,"print_margin":"0.5in","print_orientation":"Portrait","print_page_size":"Letter","sequence":[],"sequence_full":[],"sequence_short":[],"updated_at":"2025-03-13T15:08:40Z"},"relationships":{"updated_by":{"data":{"type":"Person","id":"95051396"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"song":{"data":{"type":"Song","id":"12327928"}}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1131208437/arrangement"}},{"type":"Key","id":"21251195","attributes":{"alternate_keys":[],"created_at":"2017-11-22T20:36:48Z","ending_key":null,"ending_minor":false,"name":null,"starting_key":"D","starting_minor":false,"updated_at":"2023-03-05T20:01:17Z"},"relationships":{"arrangement":{"data":{"type":"Arrangement","id":"13840808"}}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314/items/1131208437/key"}}],"meta":{"total_count":14,"count":14,"can_include":["arrangement","item_notes","item_times","key","media","selected_attachment","song"],"parent":{"id":"82934314","type":"Plan"}}}
\ No newline at end of file diff --git a/data/service-types.json b/data/service-types.json new file mode 100644 index 0000000..256ad06 --- /dev/null +++ b/data/service-types.json @@ -0,0 +1 @@ +{"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types"},"data":[{"type":"ServiceType","id":"291481","attributes":{"archived_at":null,"attachment_types_enabled":true,"background_check_permissions":"default","comment_permissions":"Scheduled Viewer","created_at":"2013-08-14T15:35:50Z","custom_item_types":[],"deleted_at":null,"frequency":"Weekly","last_plan_from":"organization","name":"Decatur ","permissions":"Editor","scheduled_publish":false,"sequence":0,"standard_item_types":[{"name":"Header","color":"#eaebeb"},{"name":"Media","color":"#ffffff"},{"name":"Song","color":"#ffffff"}],"updated_at":"2023-12-06T16:16:50Z"},"relationships":{"parent":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291481"}},{"type":"ServiceType","id":"291539","attributes":{"archived_at":null,"attachment_types_enabled":true,"background_check_permissions":"default","comment_permissions":"Scheduled Viewer","created_at":"2013-08-14T17:23:53Z","custom_item_types":[],"deleted_at":null,"frequency":"Weekly","last_plan_from":"organization","name":"Berne","permissions":"Editor","scheduled_publish":false,"sequence":0,"standard_item_types":[{"name":"Header","color":"#eaebeb"},{"name":"Media","color":"#ffffff"},{"name":"Song","color":"#ffffff"}],"updated_at":"2019-03-10T11:39:22Z"},"relationships":{"parent":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539"}},{"type":"ServiceType","id":"647998","attributes":{"archived_at":null,"attachment_types_enabled":false,"background_check_permissions":"default","comment_permissions":"Scheduled Viewer","created_at":"2016-10-19T21:00:32Z","custom_item_types":[],"deleted_at":null,"frequency":"Weekly","last_plan_from":"organization","name":"High School","permissions":"Editor","scheduled_publish":false,"sequence":0,"standard_item_types":[{"name":"Header","color":"#eaebeb"},{"name":"Media","color":"#ffffff"},{"name":"Song","color":"#ffffff"}],"updated_at":"2016-10-19T21:00:32Z"},"relationships":{"parent":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/647998"}},{"type":"ServiceType","id":"1164771","attributes":{"archived_at":null,"attachment_types_enabled":false,"background_check_permissions":"default","comment_permissions":"Scheduled Viewer","created_at":"2021-08-27T11:30:08Z","custom_item_types":[],"deleted_at":null,"frequency":"None","last_plan_from":"organization","name":"worship night","permissions":"Editor","scheduled_publish":false,"sequence":0,"standard_item_types":[{"name":"Header","color":"#eaebeb"},{"name":"Media","color":"#ffffff"},{"name":"Song","color":"#ffffff"}],"updated_at":"2025-09-16T20:15:11Z"},"relationships":{"parent":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/1164771"}},{"type":"ServiceType","id":"1572501","attributes":{"archived_at":null,"attachment_types_enabled":false,"background_check_permissions":"default","comment_permissions":"Scheduled Viewer","created_at":"2024-12-10T23:04:01Z","custom_item_types":[],"deleted_at":null,"frequency":"Weekly","last_plan_from":"organization","name":"Security - Decatur","permissions":"Editor","scheduled_publish":false,"sequence":0,"standard_item_types":[{"name":"Header","color":"#eaebeb"},{"name":"Media","color":"#ffffff"},{"name":"Song","color":"#ffffff"}],"updated_at":"2025-04-09T16:12:06Z"},"relationships":{"parent":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/1572501"}},{"type":"ServiceType","id":"1627193","attributes":{"archived_at":null,"attachment_types_enabled":false,"background_check_permissions":"default","comment_permissions":"Scheduled Viewer","created_at":"2025-04-29T19:26:27Z","custom_item_types":[],"deleted_at":null,"frequency":"None","last_plan_from":"organization","name":"Project Worship","permissions":"Editor","scheduled_publish":false,"sequence":0,"standard_item_types":[{"name":"Header","color":"#eaebeb"},{"name":"Media","color":"#ffffff"},{"name":"Song","color":"#ffffff"}],"updated_at":"2025-04-29T19:31:56Z"},"relationships":{"parent":{"data":null}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/1627193"}}],"included":[],"meta":{"total_count":6,"count":6,"can_order_by":["sequence","name"],"can_query_by":["id","name","parent_id"],"can_include":["time_preference_options"],"can_filter":["no_parent"],"parent":{"id":"114134","type":"Organization"}}}
\ No newline at end of file diff --git a/data/upcoming-plans.json b/data/upcoming-plans.json new file mode 100644 index 0000000..07ad886 --- /dev/null +++ b/data/upcoming-plans.json @@ -0,0 +1 @@ +{"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans?filter=future"},"data":[{"type":"Plan","id":"82934314","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:06:18Z","dates":"October 19, 2025","files_expire_at":"2025-11-03T12:00:00Z","items_count":14,"last_time_at":"2025-10-19T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":13,"planning_center_url":"https://services.planningcenteronline.com/plans/82934314","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Almost True","service_time_count":2,"short_dates":"Oct 19","sort_date":"2025-10-19T09:30:00Z","title":"When Self-Love Is Selfish","total_length":4233,"updated_at":"2025-10-14T22:32:36Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934281"}},"next_plan":{"data":{"type":"Plan","id":"82934328"}},"series":{"data":{"type":"Series","id":"2764284"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"3931264"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934314","html":"https://services.planningcenteronline.com/plans/82934314"}},{"type":"Plan","id":"82934328","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:06:35Z","dates":"October 26, 2025","files_expire_at":"2025-11-10T12:00:00Z","items_count":13,"last_time_at":"2025-10-26T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":12,"planning_center_url":"https://services.planningcenteronline.com/plans/82934328","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Almost True","service_time_count":2,"short_dates":"Oct 26","sort_date":"2025-10-26T09:30:00Z","title":"Why Don’t I Feel Like Enough?","total_length":3989,"updated_at":"2025-10-14T16:21:35Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934314"}},"next_plan":{"data":{"type":"Plan","id":"82934359"}},"series":{"data":{"type":"Series","id":"2764284"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"95051396"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934328","html":"https://services.planningcenteronline.com/plans/82934328"}},{"type":"Plan","id":"82934359","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:07:06Z","dates":"November 2, 2025","files_expire_at":"2025-11-17T12:00:00Z","items_count":13,"last_time_at":"2025-11-02T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":12,"planning_center_url":"https://services.planningcenteronline.com/plans/82934359","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Almost True","service_time_count":2,"short_dates":"Nov 2","sort_date":"2025-11-02T09:30:00Z","title":"Why Doesn’t God Give Me What I Want?","total_length":3673,"updated_at":"2025-10-10T02:19:54Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934328"}},"next_plan":{"data":{"type":"Plan","id":"82934399"}},"series":{"data":{"type":"Series","id":"2764284"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"95051396"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934359","html":"https://services.planningcenteronline.com/plans/82934359"}},{"type":"Plan","id":"82934399","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:07:29Z","dates":"November 9, 2025","files_expire_at":"2025-11-24T12:00:00Z","items_count":14,"last_time_at":"2025-11-09T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":12,"planning_center_url":"https://services.planningcenteronline.com/plans/82934399","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Almost True","service_time_count":2,"short_dates":"Nov 9","sort_date":"2025-11-09T09:30:00Z","title":"The Problem With Perfectionism","total_length":3502,"updated_at":"2025-10-14T16:30:31Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934359"}},"next_plan":{"data":{"type":"Plan","id":"82934414"}},"series":{"data":{"type":"Series","id":"2764284"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"95051396"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934399","html":"https://services.planningcenteronline.com/plans/82934399"}},{"type":"Plan","id":"82934414","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:07:54Z","dates":"November 16, 2025","files_expire_at":"2025-12-01T12:00:00Z","items_count":13,"last_time_at":"2025-11-16T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":12,"planning_center_url":"https://services.planningcenteronline.com/plans/82934414","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Unshakable","service_time_count":2,"short_dates":"Nov 16","sort_date":"2025-11-16T09:30:00Z","title":"Living for Jesus in a Culture of Compromise","total_length":3090,"updated_at":"2025-10-14T16:33:54Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934399"}},"next_plan":{"data":{"type":"Plan","id":"82934432"}},"series":{"data":{"type":"Series","id":"2764305"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"95051396"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934414","html":"https://services.planningcenteronline.com/plans/82934414"}},{"type":"Plan","id":"82934432","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:08:11Z","dates":"November 23, 2025","files_expire_at":"2025-12-08T12:00:00Z","items_count":13,"last_time_at":"2025-11-23T11:00:00Z","multi_day":false,"needed_positions_count":1,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":11,"planning_center_url":"https://services.planningcenteronline.com/plans/82934432","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Unshakable","service_time_count":2,"short_dates":"Nov 23","sort_date":"2025-11-23T09:30:00Z","title":"When You’re Under Attack","total_length":3687,"updated_at":"2025-10-14T16:34:53Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934414"}},"next_plan":{"data":{"type":"Plan","id":"82934448"}},"series":{"data":{"type":"Series","id":"2764305"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"95051396"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934432","html":"https://services.planningcenteronline.com/plans/82934432"}},{"type":"Plan","id":"82934448","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:08:43Z","dates":"November 30, 2025","files_expire_at":"2025-12-15T12:00:00Z","items_count":13,"last_time_at":"2025-11-30T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":0,"planning_center_url":"https://services.planningcenteronline.com/plans/82934448","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Unshakable","service_time_count":2,"short_dates":"Nov 30","sort_date":"2025-11-30T09:30:00Z","title":"Anxious Hearts, Fearless Faith","total_length":3480,"updated_at":"2025-08-26T16:08:44Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934432"}},"next_plan":{"data":{"type":"Plan","id":"82934561"}},"series":{"data":{"type":"Series","id":"2764305"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"3825437"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934448","html":"https://services.planningcenteronline.com/plans/82934448"}},{"type":"Plan","id":"82934561","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:09:59Z","dates":"December 7, 2025","files_expire_at":"2025-12-22T12:00:00Z","items_count":13,"last_time_at":"2025-12-07T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":0,"planning_center_url":"https://services.planningcenteronline.com/plans/82934561","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Holy Moments","service_time_count":2,"short_dates":"Dec 7","sort_date":"2025-12-07T09:30:00Z","title":"When It’s Hard to Obey","total_length":3480,"updated_at":"2025-08-26T16:10:01Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934448"}},"next_plan":{"data":{"type":"Plan","id":"82934598"}},"series":{"data":{"type":"Series","id":"2764322"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"3825437"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934561","html":"https://services.planningcenteronline.com/plans/82934561"}},{"type":"Plan","id":"82934598","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:10:27Z","dates":"December 14, 2025","files_expire_at":"2025-12-29T12:00:00Z","items_count":13,"last_time_at":"2025-12-14T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":0,"planning_center_url":"https://services.planningcenteronline.com/plans/82934598","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Holy Moments","service_time_count":2,"short_dates":"Dec 14","sort_date":"2025-12-14T09:30:00Z","title":"A Moment of Surrender","total_length":3480,"updated_at":"2025-08-26T16:10:29Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934561"}},"next_plan":{"data":{"type":"Plan","id":"82934630"}},"series":{"data":{"type":"Series","id":"2764322"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"3825437"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934598","html":"https://services.planningcenteronline.com/plans/82934598"}},{"type":"Plan","id":"82934630","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:10:57Z","dates":"December 21, 2025","files_expire_at":"2026-01-05T12:00:00Z","items_count":13,"last_time_at":"2025-12-21T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":0,"planning_center_url":"https://services.planningcenteronline.com/plans/82934630","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":"Holy Moments","service_time_count":2,"short_dates":"Dec 21","sort_date":"2025-12-21T09:30:00Z","title":"To Hell With Hesitation","total_length":3480,"updated_at":"2025-08-26T16:10:58Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934598"}},"next_plan":{"data":{"type":"Plan","id":"82934900"}},"series":{"data":{"type":"Series","id":"2764322"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"3825437"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934630","html":"https://services.planningcenteronline.com/plans/82934630"}},{"type":"Plan","id":"82934779","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:13:34Z","dates":"December 28, 2025","files_expire_at":"2026-01-12T12:00:00Z","items_count":13,"last_time_at":"2025-12-28T11:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":2,"permissions":"Editor","plan_notes_count":0,"plan_people_count":0,"planning_center_url":"https://services.planningcenteronline.com/plans/82934779","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":3,"reminders_disabled":false,"series_title":null,"service_time_count":2,"short_dates":"Dec 28","sort_date":"2025-12-28T09:30:00Z","title":"Stand Alone","total_length":3480,"updated_at":"2025-08-26T16:13:35Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934900"}},"next_plan":{"data":null},"series":{"data":null},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"3825437"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934779","html":"https://services.planningcenteronline.com/plans/82934779"}},{"type":"Plan","id":"82934900","attributes":{"can_view_order":true,"created_at":"2025-08-26T16:15:14Z","dates":"December 24, 2025","files_expire_at":"2026-01-08T18:00:00Z","items_count":13,"last_time_at":"2025-12-24T17:00:00Z","multi_day":false,"needed_positions_count":0,"other_time_count":1,"permissions":"Editor","plan_notes_count":0,"plan_people_count":0,"planning_center_url":"https://services.planningcenteronline.com/plans/82934900","prefers_order_view":true,"public":false,"rehearsable":true,"rehearsal_time_count":1,"reminders_disabled":false,"series_title":"Christmas Eve","service_time_count":2,"short_dates":"Dec 24","sort_date":"2025-12-24T15:30:00Z","title":null,"total_length":3480,"updated_at":"2025-08-26T16:15:16Z"},"relationships":{"service_type":{"data":{"type":"ServiceType","id":"291539"}},"previous_plan":{"data":{"type":"Plan","id":"82934630"}},"next_plan":{"data":{"type":"Plan","id":"82934779"}},"series":{"data":{"type":"Series","id":"2764346"}},"created_by":{"data":{"type":"Person","id":"3825437"}},"updated_by":{"data":{"type":"Person","id":"3825437"}},"linked_publishing_episode":{"data":null},"attachment_types":{"data":[]}},"links":{"self":"https://api.planningcenteronline.com/services/v2/service_types/291539/plans/82934900","html":"https://services.planningcenteronline.com/plans/82934900"}}],"included":[],"meta":{"total_count":12,"count":12,"can_order_by":["title","created_at","updated_at","sort_date"],"can_query_by":["id","created_at","updated_at","series_title","title"],"can_include":["contributors","my_schedules","plan_times","series"],"can_filter":["future","past","after","before","no_dates"],"parent":{"id":"291539","type":"ServiceType"}}}
\ No newline at end of file diff --git a/src/pke-at-common.cpp b/src/pke-at-common.cpp index 8372bcc..1df5521 100644 --- a/src/pke-at-common.cpp +++ b/src/pke-at-common.cpp @@ -53,3 +53,130 @@ AssetHandle pke_at_audio_get_or_generate_sawtooth(double pitch_freq, double dura handle = AM_Register(key, PKE_ASSET_TYPE_AUDIO, bytes, len, 64, &details); return handle; } + +int case_insensitive_equal(const char *lhs, const char *rhs) { + while (*lhs && *rhs) { + if (tolower((unsigned char)*lhs) != tolower((unsigned char)*rhs)) { + return 0; + } + lhs++; + rhs++; + } + return *lhs == *rhs; +} + +PKE_AT_KEY_INDEX parse_key_from_string(const char *key) { + switch (key[0]) { + case 'c': + case 'C': + if (strlen(key) == 1 || key[1] != '#') { + return PKE_AT_KEY_INDEX_C; + } + if (key[1] == '#') { + return PKE_AT_KEY_INDEX_C_SHARP; + } + break; + case 'd': + case 'D': + if (strlen(key) == 1 || (key[1] != 'b' && key[1] != '#')) { + return PKE_AT_KEY_INDEX_D; + } + if (key[1] == 'b') { + return PKE_AT_KEY_INDEX_D_FLAT; + } + if (key[1] == '#') { + return PKE_AT_KEY_INDEX_D_SHARP; + } + break; + case 'e': + case 'E': + if (strlen(key) == 1 || key[1] != 'b') { + return PKE_AT_KEY_INDEX_E; + } + if (key[1] == 'b') { + return PKE_AT_KEY_INDEX_E_FLAT; + } + break; + case 'f': + case 'F': + if (strlen(key) == 1 || (key[1] != 'b' && key[1] != '#')) { + return PKE_AT_KEY_INDEX_F; + } + if (key[1] == '#') { + return PKE_AT_KEY_INDEX_F_SHARP; + } + break; + case 'g': + case 'G': + if (strlen(key) == 1 || (key[1] != 'b' && key[1] != '#')) { + return PKE_AT_KEY_INDEX_G; + } + if (key[1] == 'b') { + return PKE_AT_KEY_INDEX_G_FLAT; + } + if (key[1] == '#') { + return PKE_AT_KEY_INDEX_G_SHARP; + } + break; + case 'a': + case 'A': + if (strlen(key) == 1 || (key[1] != 'b' && key[1] != '#')) { + return PKE_AT_KEY_INDEX_A; + } + if (key[1] == 'b') { + return PKE_AT_KEY_INDEX_A_FLAT; + } + if (key[1] == '#') { + return PKE_AT_KEY_INDEX_A_SHARP; + } + break; + case 'b': + case 'B': + if (strlen(key) == 1 || key[1] != 'b') { + return PKE_AT_KEY_INDEX_B; + } + if (key[1] == 'b') { + return PKE_AT_KEY_INDEX_B_FLAT; + } + default: + break; + } + return PKE_AT_KEY_INDEX_NONE; +} + +PKE_AT_SECTION_TYPE_INDEX parse_section_type_from_string(const char *section) { + if (case_insensitive_equal(section, "verse")) { + return PKE_AT_SECTION_TYPE_INDEX_VERSE; + } + if (case_insensitive_equal(section, "chorus")) { + return PKE_AT_SECTION_TYPE_INDEX_CHORUS; + } + if (case_insensitive_equal(section, "bridge")) { + return PKE_AT_SECTION_TYPE_INDEX_BRIDGE; + } + if (case_insensitive_equal(section, "intro")) { + return PKE_AT_SECTION_TYPE_INDEX_INTRO; + } + if (case_insensitive_equal(section, "outro")) { + return PKE_AT_SECTION_TYPE_INDEX_OUTRO; + } + if (case_insensitive_equal(section, "end")) { + return PKE_AT_SECTION_TYPE_INDEX_END; + } + if (case_insensitive_equal(section, "ending")) { + return PKE_AT_SECTION_TYPE_INDEX_ENDING; + } + if (case_insensitive_equal(section, "instrumental")) { + return PKE_AT_SECTION_TYPE_INDEX_INSTRUMENTAL; + } + if (case_insensitive_equal(section, "interlude")) { + return PKE_AT_SECTION_TYPE_INDEX_INTERLUDE; + } + if (case_insensitive_equal(section, "refrain")) { + return PKE_AT_SECTION_TYPE_INDEX_REFRAIN; + } + if (case_insensitive_equal(section, "tag")) { + return PKE_AT_SECTION_TYPE_INDEX_TAG; + } + return PKE_AT_SECTION_TYPE_INDEX_NONE; +} diff --git a/src/pke-at-common.hpp b/src/pke-at-common.hpp index a7b9a69..524cde3 100644 --- a/src/pke-at-common.hpp +++ b/src/pke-at-common.hpp @@ -1,12 +1,17 @@ #ifndef PKE_AT_PKE_AT_COMMON_HPP #define PKE_AT_PKE_AT_COMMON_HPP +#include "pke-at-setlist-types.hpp" #include "pke/asset-manager.hpp" #include <cstdint> void pke_at_bpm_reset(uint8_t bpm); +int case_insensitive_equal(const char *lhs, const char *rhs); +PKE_AT_KEY_INDEX parse_key_from_string(const char *key_str); +PKE_AT_SECTION_TYPE_INDEX parse_section_type_from_string(const char *section); + AssetHandle pke_at_audio_get_or_generate_sawtooth(double pitch_freq, double duration); #endif /* PKE_AT_PKE_AT_COMMON_HPP */ diff --git a/src/pke-at-data-interface-types.hpp b/src/pke-at-data-interface-types.hpp new file mode 100644 index 0000000..e83af26 --- /dev/null +++ b/src/pke-at-data-interface-types.hpp @@ -0,0 +1,68 @@ +#ifndef PKE_AT_PKE_AT_DATA_INTERFACE_TYPES_HPP +#define PKE_AT_PKE_AT_DATA_INTERFACE_TYPES_HPP + +#include "pke-at-setlist-types.hpp" +#include <pke/pk.h> + +union di_data_id { + long id_long; +}; + +struct di_service_type_details { + di_data_id id; + pk_cstr name; +}; +struct di_service_type { + di_service_type_details details{}; +}; + +struct di_plan_details { + di_data_id id; + time_t date; + pk_cstr title; + pk_cstr series_title; +}; +struct di_plan { + di_plan_details details{}; +}; + +struct di_song_details { + di_data_id id; + pk_cstr title; + long ccli; +}; +struct di_song { + di_song_details details{}; +}; +struct di_arrangement_details { + di_data_id id; + pk_cstr title; + pk_arr_t<PKE_AT_SECTION_TYPE_INDEX> sequence; + uint8_t beats_per_minute; + uint8_t beats_per_bar; + PKE_AT_KEY_INDEX chord_chart_key; +}; +struct di_arrangement { + di_arrangement_details details{}; +}; +struct di_arrangement_key_details { + di_data_id id; + PKE_AT_KEY_INDEX key; +}; +struct di_arrangement_key { + di_arrangement_key_details details{}; +}; + +struct di_plan_item_details { + di_data_id id; + PKE_AT_KEY_INDEX key; + uint8_t sequence; +}; +struct di_plan_item { + di_plan_item_details details{}; + di_song song{}; + di_arrangement arrangement{}; + di_arrangement_key key{}; +}; + +#endif /* PKE_AT_PKE_AT_DATA_INTERFACE_TYPES_HPP */ diff --git a/src/pke-at-data-interface.hpp b/src/pke-at-data-interface.hpp new file mode 100644 index 0000000..ec10747 --- /dev/null +++ b/src/pke-at-data-interface.hpp @@ -0,0 +1,38 @@ +#ifndef PKE_AT_PKE_AT_DATA_INTERFACE_HPP +#define PKE_AT_PKE_AT_DATA_INTERFACE_HPP + +#include "pke-at-data-interface-types.hpp" + +enum pke_at_data_interface_result_code { + pke_at_data_interface_result_code_none = 0, + pke_at_data_interface_result_code_success = 1, + pke_at_data_interface_result_code_error = 2, +}; + +struct pke_at_data_interface_response { + pke_at_data_interface_result_code result_code; +}; + +template <typename T> +struct pke_at_data_interface_response_t { + pke_at_data_interface_result_code result_code; + T *value; +}; + +#define FPADIR std::future<pke_at_data_interface_response> +#define FPADIRT(T) std::future<pke_at_data_interface_response_t<T>> +#define PPADIR std::promise<pke_at_data_interface_response> +#define PPADIRT(T) std::promise<pke_at_data_interface_response_t<T>> + +struct pke_at_data_interface { + pke_at_data_interface() = default; + virtual ~pke_at_data_interface() = default; + virtual void init() const = 0; + virtual void teardown() const = 0; + virtual FPADIRT(pk_arr_t<di_service_type>) get_service_types() const = 0; + virtual FPADIRT(pk_arr_t<di_plan>) get_plans_upcoming_from_service_type() const = 0; + virtual FPADIRT(pk_arr_t<di_plan_item>) get_plan_items() const = 0; + // virtual FPADIRT(pk_arr_t<pke_at_plan_details>) get_song_arrangements() const = 0; +}; + +#endif /* PKE_AT_PKE_AT_DATA_INTERFACE_HPP */ diff --git a/src/pke-at-data-parser.cpp b/src/pke-at-data-parser.cpp new file mode 100644 index 0000000..da70e4e --- /dev/null +++ b/src/pke-at-data-parser.cpp @@ -0,0 +1,218 @@ + +#include "pke-at-data-parser.hpp" +#include "pke-at-common.hpp" + +#include <ctime> +#include <nlohmann/json.hpp> +#include <sstream> + +using json = nlohmann::json; + +pk_arr_t<di_service_type> pke_at_data_parser_service_types(char *data) { + PK_STN_RES stn_res; + pk_arr_t<di_service_type> ret{}; + json j = json::parse(data); + char *val; + std::string s; + if (!j.contains("data") || j.at("data").is_null()) { + fprintf(stderr, "[pke_at_data_parser_service_types] no 'data'\n"); + return {}; + } + json dat = j.at("data"); + for (json::iterator it = dat.begin(); it != dat.end(); ++it) { + di_service_type obj{}; + it->at("id").get_to(s); + stn_res = pk_stn(&obj.details.id.id_long, s.c_str(), nullptr); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[pke_at_data_parser_service_types] failed to parse id: %i\n", stn_res); + return {}; + } + json attr = (*it).at("attributes"); + attr.at("name").get_to(s); + obj.details.name.length = s.length(); + obj.details.name.reserved = s.length() + 1; + val = pk_new_arr<char>(obj.details.name.reserved); + std::strncpy(val, s.c_str(), obj.details.name.reserved); + obj.details.name.val = val; + pk_arr_append_t<di_service_type>(&ret, obj); + } + return ret; +} + +pk_arr_t<di_plan> pke_at_data_parser_plans(char *data) { + PK_STN_RES stn_res; + pk_arr_t<di_plan> ret{}; + json j = json::parse(data); + char *val; + std::string s; + if (!j.contains("data") || j.at("data").is_null()) { + fprintf(stderr, "[pke_at_data_parser_plans] no 'data'\n"); + return {}; + } + json dat = j.at("data"); + for (json::iterator it = dat.begin(); it != dat.end(); ++it) { + di_plan obj{}; + it->at("id").get_to(s); + stn_res = pk_stn(&obj.details.id.id_long, s.c_str(), nullptr); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[pke_at_data_parser_plans] failed to parse id: %i\n", stn_res); + return {}; + } + json attr = (*it).at("attributes"); + attr.at("sort_date").get_to(s); + std::istringstream ss(s); + std::tm t{}; + ss >> std::get_time(&t, "%Y-%m-%dT%H:%M:%SZ"); + obj.details.date = std::mktime(&t); + if (attr.contains("title") && !attr.at("title").is_null()) { + attr.at("title").get_to(s); + obj.details.title.length = s.length(); + obj.details.title.reserved = s.length() + 1; + val = pk_new_arr<char>(obj.details.title.reserved); + std::strncpy(val, s.c_str(), obj.details.title.reserved); + obj.details.title.val = val; + } + if (attr.contains("series_title") && !attr.at("series_title").is_null()) { + attr.at("series_title").get_to(s); + obj.details.series_title.length = s.length(); + obj.details.series_title.reserved = s.length() + 1; + val = pk_new_arr<char>(obj.details.series_title.reserved); + std::strncpy(val, s.c_str(), obj.details.series_title.reserved); + obj.details.series_title.val = val; + } + pk_arr_append_t<di_plan>(&ret, obj); + } + return ret; +} + +pk_arr_t<di_plan_item> pke_at_data_parser_plan_items(char *data) { + PK_STN_RES stn_res; + pk_arr_t<di_plan_item> ret{}; + json j = json::parse(data); + char *val; + std::string s; + long id, id_song, id_arrangement, id_key; + if (!j.contains("data") || j.at("data").is_null()) { + fprintf(stderr, "[pke_at_data_parser_plan_items] no 'data'\n"); + return {}; + } + json dat = j.at("data"); + if (!j.contains("included") || j.at("included").is_null()) { + fprintf(stderr, "[pke_at_data_parser_plan_items] no 'included'\n"); + return {}; + } + json incl = j.at("included"); + + for (json::iterator it = dat.begin(); it != dat.end(); ++it) { + di_plan_item obj{}; + + id_song = -1; + id_arrangement = -1; + id_key = -1; + + json attr = it->at("attributes"); + if (!attr.contains("item_type") || attr.at("item_type").is_null()) { + continue; + } + attr.at("item_type").get_to(s); + if (!case_insensitive_equal(s.c_str(), "song")) { + continue; + } + + it->at("id").get_to(s); + stn_res = pk_stn(&obj.details.id.id_long, s.c_str(), nullptr); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[pke_at_data_parser_plan_items] failed to parse id: %i\n", stn_res); + return {}; + } + + if (attr.contains("key_name") && !attr.at("key_name").is_null()) { + attr.at("key_name").get_to(s); + obj.details.key = parse_key_from_string(s.c_str()); + } + + attr.at("sequence").get_to(obj.details.sequence); + + json rel_song = it->at("relationships").at("song").at("data"); + json rel_arrangement = it->at("relationships").at("arrangement").at("data"); + json rel_key = it->at("relationships").at("key").at("data"); + + rel_song.at("id").get_to(s); + stn_res = pk_stn(&id_song, s.c_str(), nullptr); + rel_arrangement.at("id").get_to(s); + stn_res = pk_stn(&id_arrangement, s.c_str(), nullptr); + rel_key.at("id").get_to(s); + stn_res = pk_stn(&id_key, s.c_str(), nullptr); + + for (json::iterator incl_it = incl.begin(); incl_it != incl.end(); ++incl_it) { + incl_it->at("type").get_to(s); + if (case_insensitive_equal(s.c_str(), "song")) { + attr = incl_it->at("attributes"); + incl_it->at("id").get_to(s); + pk_stn(&id, s.c_str(), nullptr); + if (id != id_song) continue; + obj.song.details.id.id_long = id; + attr.at("ccli_number").get_to(obj.song.details.ccli); + if (attr.contains("title") && !attr.at("title").is_null()) { + attr.at("title").get_to(s); + obj.song.details.title.length = s.length(); + obj.song.details.title.reserved = s.length() + 1; + val = pk_new_arr<char>(obj.song.details.title.reserved); + std::strncpy(val, s.c_str(), obj.song.details.title.reserved); + obj.song.details.title.val = val; + } + continue; + } + if (case_insensitive_equal(s.c_str(), "arrangement")) { + attr = incl_it->at("attributes"); + incl_it->at("id").get_to(s); + pk_stn(&id, s.c_str(), nullptr); + if (id != id_arrangement) continue; + obj.arrangement.details.id.id_long = id; + if (attr.contains("bpm") && !attr.at("bpm").is_null()) { + attr.at("bpm").get_to(obj.arrangement.details.beats_per_minute); + } + if (attr.contains("meter") && !attr.at("meter").is_null()) { + attr.at("meter").get_to(s); + char cc[2] = { s.at(0), '\0'}; + pk_stn(&obj.arrangement.details.beats_per_bar, cc, nullptr); + } + if (attr.contains("chord_chart_key") && !attr.at("chord_chart_key").is_null()) { + attr.at("chord_chart_key").get_to(s); + obj.arrangement.details.chord_chart_key = parse_key_from_string(s.c_str()); + } + if (attr.contains("name") && !attr.at("name").is_null()) { + attr.at("name").get_to(s); + obj.arrangement.details.title.length = s.length(); + obj.arrangement.details.title.reserved = s.length() + 1; + val = pk_new_arr<char>(obj.arrangement.details.title.reserved); + std::strncpy(val, s.c_str(), obj.arrangement.details.title.reserved); + obj.arrangement.details.title.val = val; + } + if (attr.contains("sequence_full") && !attr.at("sequence_full").is_null()) { + for (json::iterator sec_it = attr.at("sequence_full").begin(); sec_it != attr.at("sequence_full").end(); ++sec_it) { + sec_it->at("label").get_to(s); + pk_arr_append_t<PKE_AT_SECTION_TYPE_INDEX>(&obj.arrangement.details.sequence, parse_section_type_from_string(s.c_str())); + } + } + continue; + } + if (case_insensitive_equal(s.c_str(), "key")) { + attr = incl_it->at("attributes"); + incl_it->at("id").get_to(s); + pk_stn(&id, s.c_str(), nullptr); + if (id != id_key) continue; + obj.key.details.id.id_long = id; + if (attr.contains("starting_key") && !attr.at("starting_key").is_null()) { + attr.at("starting_key").get_to(s); + obj.key.details.key = parse_key_from_string(s.c_str()); + } + continue; + } + fprintf(stderr, "[pke_at_data_parser_plan_items] unhandled include \"type\": '%s'\n", s.c_str()); + } + + pk_arr_append_t<di_plan_item>(&ret, obj); + } + return ret; +} diff --git a/src/pke-at-data-parser.hpp b/src/pke-at-data-parser.hpp new file mode 100644 index 0000000..fd491ef --- /dev/null +++ b/src/pke-at-data-parser.hpp @@ -0,0 +1,11 @@ +#ifndef PKE_AT_PKE_AT_DATA_PARSER_HPP +#define PKE_AT_PKE_AT_DATA_PARSER_HPP + +#include "pke-at-data-interface-types.hpp" +#include <pke/pk.h> + +pk_arr_t<di_service_type> pke_at_data_parser_service_types(char *data); +pk_arr_t<di_plan> pke_at_data_parser_plans(char *data); +pk_arr_t<di_plan_item> pke_at_data_parser_plan_items(char *data); + +#endif /* PKE_AT_PKE_AT_DATA_PARSER_HPP */ diff --git a/src/pke-at-data-stub.cpp b/src/pke-at-data-stub.cpp new file mode 100644 index 0000000..c36583f --- /dev/null +++ b/src/pke-at-data-stub.cpp @@ -0,0 +1,61 @@ + +#include "pke-at-data-stub.hpp" + +#include "../data/service_types_json.h" +#include "../data/upcoming_plans_json.h" +#include "../data/plan_items_json.h" + +#include "pke-at-data-parser.hpp" + +void pke_at_data_stub::init() const { +} + +void pke_at_data_stub::teardown() const { +}; + +FPADIRT(pk_arr_t<di_service_type>) +pke_at_data_stub::get_service_types() const { + PPADIRT(pk_arr_t<di_service_type>) ret{}; + std::thread([&ret]() { + pke_at_data_interface_response_t<pk_arr_t<di_service_type>> val{}; + val.result_code = pke_at_data_interface_result_code_success; + val.value = pk_new<pk_arr_t<di_service_type>>(); + *val.value = pke_at_data_parser_service_types((char*)data_service_types_json); + ret.set_value(val); + }).detach(); + return ret.get_future(); +}; + +FPADIRT(pk_arr_t<di_plan>) +pke_at_data_stub::get_plans_upcoming_from_service_type() const { + PPADIRT(pk_arr_t<di_plan>) ret{}; + std::thread([&ret]() { + pke_at_data_interface_response_t<pk_arr_t<di_plan>> val{}; + val.result_code = pke_at_data_interface_result_code_success; + val.value = pk_new<pk_arr_t<di_plan>>(); + *val.value = pke_at_data_parser_plans((char*)data_upcoming_plans_json); + ret.set_value(val); + }).detach(); + return ret.get_future(); +} + +FPADIRT(pk_arr_t<di_plan_item>) +pke_at_data_stub::get_plan_items() const { + PPADIRT(pk_arr_t<di_plan_item>) ret{}; + std::thread([&ret]() { + pke_at_data_interface_response_t<pk_arr_t<di_plan_item>> val{}; + val.result_code = pke_at_data_interface_result_code_success; + val.value = pk_new<pk_arr_t<di_plan_item>>(); + *val.value = pke_at_data_parser_plan_items((char*)data_plan_items_json); + ret.set_value(val); + }).detach(); + return ret.get_future(); +} + +/* +PPADIRT(pk_arr_t<pke_at_plan_details>) +pke_at_data_stub::get_song_arrangements() const { + PPADIRT(pk_arr_t<pke_at_plan_details>) ret{}; + return ret; +}; +*/ diff --git a/src/pke-at-data-stub.hpp b/src/pke-at-data-stub.hpp new file mode 100644 index 0000000..4f8d929 --- /dev/null +++ b/src/pke-at-data-stub.hpp @@ -0,0 +1,15 @@ +#ifndef PKE_AT_PKE_AT_DATA_STUB_HPP +#define PKE_AT_PKE_AT_DATA_STUB_HPP + +#include "pke-at-data-interface.hpp" + +class pke_at_data_stub : public pke_at_data_interface { + void init() const override; + void teardown() const override; + FPADIRT(pk_arr_t<di_service_type>) get_service_types() const override; + FPADIRT(pk_arr_t<di_plan>) get_plans_upcoming_from_service_type() const override; + FPADIRT(pk_arr_t<di_plan_item>) get_plan_items() const override; + // FPADIRT(pk_arr_t<pke_at_plan_details>) get_song_arrangements() const override; +}; + +#endif /* PKE_AT_PKE_AT_DATA_STUB_HPP */ diff --git a/src/pke-at-setlist-types.hpp b/src/pke-at-setlist-types.hpp index 0ab6815..90c86d0 100644 --- a/src/pke-at-setlist-types.hpp +++ b/src/pke-at-setlist-types.hpp @@ -10,8 +10,12 @@ enum PKE_AT_SECTION_TYPE_INDEX { PKE_AT_SECTION_TYPE_INDEX_BRIDGE, PKE_AT_SECTION_TYPE_INDEX_INTRO, PKE_AT_SECTION_TYPE_INDEX_OUTRO, + PKE_AT_SECTION_TYPE_INDEX_END, + PKE_AT_SECTION_TYPE_INDEX_ENDING = PKE_AT_SECTION_TYPE_INDEX_END, PKE_AT_SECTION_TYPE_INDEX_INSTRUMENTAL, PKE_AT_SECTION_TYPE_INDEX_INTERLUDE, + PKE_AT_SECTION_TYPE_INDEX_REFRAIN, + PKE_AT_SECTION_TYPE_INDEX_TAG, PKE_AT_SECTION_TYPE_INDEX_COUNT, }; @@ -32,8 +36,31 @@ struct pke_at_section { pke_at_section_details details{}; }; +enum PKE_AT_KEY_INDEX { + PKE_AT_KEY_INDEX_NONE = 0, + PKE_AT_KEY_INDEX_C, + PKE_AT_KEY_INDEX_C_SHARP, + PKE_AT_KEY_INDEX_D_FLAT, + PKE_AT_KEY_INDEX_D, + PKE_AT_KEY_INDEX_D_SHARP, + PKE_AT_KEY_INDEX_E_FLAT, + PKE_AT_KEY_INDEX_E, + PKE_AT_KEY_INDEX_F, + PKE_AT_KEY_INDEX_F_SHARP, + PKE_AT_KEY_INDEX_G_FLAT, + PKE_AT_KEY_INDEX_G, + PKE_AT_KEY_INDEX_G_SHARP, + PKE_AT_KEY_INDEX_A_FLAT, + PKE_AT_KEY_INDEX_A, + PKE_AT_KEY_INDEX_A_SHARP, + PKE_AT_KEY_INDEX_B_FLAT, + PKE_AT_KEY_INDEX_B, + PKE_AT_KEY_INDEX_COUNT, +}; + struct pke_at_song_details { pk_uuid uuid; + enum PKE_AT_KEY_INDEX key; long ccli; pk_cstr title; pk_cstr arrangement; diff --git a/tests/pke-at-test-data-parser.cpp b/tests/pke-at-test-data-parser.cpp new file mode 100644 index 0000000..a6a42cb --- /dev/null +++ b/tests/pke-at-test-data-parser.cpp @@ -0,0 +1,241 @@ + +#include "pke-at-test-data-parser.h" +#include "../src/pke-at-data-parser.hpp" +#include "../data/service_types_json.h" +#include "../data/upcoming_plans_json.h" +#include "../data/plan_items_json.h" +#include "pke/pk.h" + +static pk_membucket *bkt = nullptr; + +void parse_test_init() { + bkt = pk_mem_bucket_create("pke-at-test-data-parser", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); + pk_mem_bucket_set_client_mem_bucket(bkt); +} +void parse_test_teardown() { + pk_mem_bucket_set_client_mem_bucket(nullptr); + pk_mem_bucket_destroy(bkt); + bkt = nullptr; +} + +int parse_test_001() { + pk_arr_t<di_service_type> service_types = pke_at_data_parser_service_types((char*)data_service_types_json); + + PK_TEST_ASSERT_EQ_RET(6, service_types.next); + + PK_TEST_ASSERT_EQ_RET(291481, service_types[0].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(291539, service_types[1].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(647998, service_types[2].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(1164771, service_types[3].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(1572501, service_types[4].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(1627193, service_types[5].details.id.id_long); + + PK_TEST_ASSERT_EQ_RET(0, strcmp("Decatur ", service_types[0].details.name.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Berne", service_types[1].details.name.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("High School", service_types[2].details.name.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("worship night", service_types[3].details.name.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Security - Decatur", service_types[4].details.name.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Project Worship", service_types[5].details.name.val)); + + return 0; +} + +int parse_test_002() { + pk_arr_t<di_plan> plans = pke_at_data_parser_plans((char*)data_upcoming_plans_json); + + PK_TEST_ASSERT_EQ_RET(12, plans.next); + + PK_TEST_ASSERT_EQ_RET(82934314, plans[0].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934328, plans[1].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934359, plans[2].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934399, plans[3].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934414, plans[4].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934432, plans[5].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934448, plans[6].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934561, plans[7].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934598, plans[8].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934630, plans[9].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934779, plans[10].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(82934900, plans[11].details.id.id_long); + + // 1760730718 + PK_TEST_ASSERT_NEQ_RET(0, plans[0].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[1].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[2].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[3].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[4].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[5].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[6].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[7].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[8].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[9].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[10].details.date); + PK_TEST_ASSERT_NEQ_RET(0, plans[11].details.date); + // after "today" + PK_TEST_ASSERT_EQ_RET(true, plans[0].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[1].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[2].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[3].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[4].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[5].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[6].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[7].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[8].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[9].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[10].details.date > 1760730718); + PK_TEST_ASSERT_EQ_RET(true, plans[11].details.date > 1760730718); + // before the new year + PK_TEST_ASSERT_EQ_RET(true, plans[0].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[1].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[2].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[3].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[4].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[5].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[6].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[7].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[8].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[9].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[10].details.date < 1767225600); + PK_TEST_ASSERT_EQ_RET(true, plans[11].details.date < 1767225600); + for (int i = 0; i < 10; ++i) { + PK_TEST_ASSERT_EQ_RET(true, plans[i].details.date < plans[i+1].details.date); + } + + PK_TEST_ASSERT_EQ_RET(0, strcmp("When Self-Love Is Selfish", plans[0].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Why Don’t I Feel Like Enough?", plans[1].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Why Doesn’t God Give Me What I Want?", plans[2].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("The Problem With Perfectionism", plans[3].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Living for Jesus in a Culture of Compromise", plans[4].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("When You’re Under Attack", plans[5].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Anxious Hearts, Fearless Faith", plans[6].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("When It’s Hard to Obey", plans[7].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("A Moment of Surrender", plans[8].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("To Hell With Hesitation", plans[9].details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Stand Alone", plans[10].details.title.val)); + PK_TEST_ASSERT_EQ_RET(nullptr, plans[11].details.title.val); + + PK_TEST_ASSERT_EQ_RET(0, strcmp("Almost True", plans[0].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Almost True", plans[1].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Almost True", plans[2].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Almost True", plans[3].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Unshakable", plans[4].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Unshakable", plans[5].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Unshakable", plans[6].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Holy Moments", plans[7].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Holy Moments", plans[8].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Holy Moments", plans[9].details.series_title.val)); + PK_TEST_ASSERT_EQ_RET(nullptr, plans[10].details.series_title.val); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Christmas Eve", plans[11].details.series_title.val)); + + return 0; +} + +int parse_test_003() { + pk_arr_t<di_plan_item> items = pke_at_data_parser_plan_items((char*)data_plan_items_json); + + PK_TEST_ASSERT_EQ_RET(4, items.next); + + PK_TEST_ASSERT_EQ_RET(1116826609, items[0].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(1116826612, items[1].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(1116826614, items[2].details.id.id_long); + PK_TEST_ASSERT_EQ_RET(1131208437, items[3].details.id.id_long); + + PK_TEST_ASSERT_EQ_RET(24030215, items[0].song.details.id.id_long); + PK_TEST_ASSERT_EQ_RET(27793425, items[0].arrangement.details.id.id_long); + PK_TEST_ASSERT_EQ_RET(44596256, items[0].key.details.id.id_long); + + PK_TEST_ASSERT_EQ_RET(22058189, items[1].song.details.id.id_long); + PK_TEST_ASSERT_EQ_RET(25398725, items[1].arrangement.details.id.id_long); + PK_TEST_ASSERT_EQ_RET(45863343, items[1].key.details.id.id_long); + + PK_TEST_ASSERT_EQ_RET(18743841, items[2].song.details.id.id_long); + PK_TEST_ASSERT_EQ_RET(21448360, items[2].arrangement.details.id.id_long); + PK_TEST_ASSERT_EQ_RET(29304181, items[2].key.details.id.id_long); + + PK_TEST_ASSERT_EQ_RET(12327928, items[3].song.details.id.id_long); + PK_TEST_ASSERT_EQ_RET(13840808, items[3].arrangement.details.id.id_long); + PK_TEST_ASSERT_EQ_RET(21251195, items[3].key.details.id.id_long); + + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_G, items[0].details.key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_G, items[1].details.key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_G, items[2].details.key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_D, items[3].details.key); + + PK_TEST_ASSERT_EQ_RET(7, items[0].details.sequence); + PK_TEST_ASSERT_EQ_RET(8, items[1].details.sequence); + PK_TEST_ASSERT_EQ_RET(9, items[2].details.sequence); + PK_TEST_ASSERT_EQ_RET(13, items[3].details.sequence); + + PK_TEST_ASSERT_EQ_RET(0, strcmp("This Is Our God", items[0].song.details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Egypt", items[1].song.details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Good Grace", items[2].song.details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("My Heart Is Yours", items[3].song.details.title.val)); + PK_TEST_ASSERT_EQ_RET(7211413, items[0].song.details.ccli); + PK_TEST_ASSERT_EQ_RET(7133348, items[1].song.details.ccli); + PK_TEST_ASSERT_EQ_RET(7122177, items[2].song.details.ccli); + PK_TEST_ASSERT_EQ_RET(7017788, items[3].song.details.ccli); + + PK_TEST_ASSERT_EQ_RET(0, strcmp("Phil Wickham", items[0].arrangement.details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Cory Asbury ", items[1].arrangement.details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Hillsong United", items[2].arrangement.details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, strcmp("Default Arrangement", items[3].arrangement.details.title.val)); + PK_TEST_ASSERT_EQ_RET(0, items[0].arrangement.details.beats_per_minute); + PK_TEST_ASSERT_EQ_RET(75, items[1].arrangement.details.beats_per_minute); + PK_TEST_ASSERT_EQ_RET(73, items[2].arrangement.details.beats_per_minute); + PK_TEST_ASSERT_EQ_RET(0, items[3].arrangement.details.beats_per_minute); + PK_TEST_ASSERT_EQ_RET(0, items[0].arrangement.details.beats_per_bar); + PK_TEST_ASSERT_EQ_RET(4, items[1].arrangement.details.beats_per_bar); + PK_TEST_ASSERT_EQ_RET(4, items[2].arrangement.details.beats_per_bar); + PK_TEST_ASSERT_EQ_RET(0, items[3].arrangement.details.beats_per_bar); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_C, items[0].arrangement.details.chord_chart_key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_NONE, items[1].arrangement.details.chord_chart_key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_G, items[2].arrangement.details.chord_chart_key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_A, items[3].arrangement.details.chord_chart_key); + PK_TEST_ASSERT_EQ_RET(0, items[0].arrangement.details.sequence.next); + PK_TEST_ASSERT_EQ_RET(0, items[1].arrangement.details.sequence.next); + PK_TEST_ASSERT_EQ_RET(11, items[2].arrangement.details.sequence.next); + PK_TEST_ASSERT_EQ_RET(0, items[3].arrangement.details.sequence.next); + for (unsigned int i = 0; i < items[2].arrangement.details.sequence.next; ++i) { + PK_TEST_ASSERT_NEQ_RET(PKE_AT_SECTION_TYPE_INDEX_NONE, items[2].arrangement.details.sequence[i]); + } + + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_G, items[0].key.details.key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_G, items[1].key.details.key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_G, items[2].key.details.key); + PK_TEST_ASSERT_EQ_RET(PKE_AT_KEY_INDEX_D, items[3].key.details.key); + + return 0; +} + +struct pk_test_group *pke_at_test_get_data_parser() { + + static const unsigned char n_tests = 3; + static pk_test tests[n_tests] = { + { + .title = "parse_test_001", + .func = parse_test_001, + .expected_result = 0, + }, + { + .title = "parse_test_002", + .func = parse_test_002, + .expected_result = 0, + }, + { + .title = "parse_test_003", + .func = parse_test_003, + .expected_result = 0, + }, + }; + + static pk_test_group g{}; + g.title = "parse-tests"; + g.group_setup = nullptr; + g.group_teardown = nullptr; + g.test_setup = parse_test_init; + g.test_teardown = parse_test_teardown; + g.tests = tests; + g.n_tests = n_tests; + + return &g; +} diff --git a/tests/pke-at-test-data-parser.h b/tests/pke-at-test-data-parser.h new file mode 100644 index 0000000..b2321ff --- /dev/null +++ b/tests/pke-at-test-data-parser.h @@ -0,0 +1,8 @@ +#ifndef PKE_AT_PKE_AT_TEST_DATA_PARSER_H +#define PKE_AT_PKE_AT_TEST_DATA_PARSER_H + +#include <pke/pk.h> + +struct pk_test_group *pke_at_test_get_data_parser(); + +#endif /* PKE_AT_PKE_AT_TEST_DATA_PARSER_H */ diff --git a/tests/pke-at-test-main.cpp b/tests/pke-at-test-main.cpp index 367bbf4..dba3d0f 100644 --- a/tests/pke-at-test-main.cpp +++ b/tests/pke-at-test-main.cpp @@ -1,5 +1,6 @@ -#include "./pke-at-test-dummy.h" +#include "pke-at-test-dummy.h" +#include "pke-at-test-data-parser.h" #include <pke/pk.h> @@ -9,10 +10,11 @@ int main(int argc, char *argv[]) (void)argv; pk_test_group_get *fns[] = { - pke_at_test_get_dummy + pke_at_test_get_dummy, + pke_at_test_get_data_parser, }; - pk_test_run_test_groups(fns, 1); + pk_test_run_test_groups(fns, 2); return 0; } |
