Power Query and Stats in Excel
Introduction
We have the ability to use Audiobookshelf’s API to export a list of items listened to for analysis or importing into other systems like Goodreads for tracking.
To do so we are going to use Excel’s Power Query functionality to pull the data in.
This will need a modern version of Excel which includes Power Query tools. Office 365 will work.
First we need to capture some information from ABS itself.
We need the following
User_ID and API key these can be found by doing the following
Log into your ABS server and click Settings

We are going to get User_ID first to do so click on Listening Sessions

Click on any of the sessions for your user

In the box that appears copy the User ID

You can Close this box down now
Now click on Users and then your User Name from the list, make sure you click on the Username itself for the next part
There should be a long API number click on the copy icon to copy this

We can now proceed to Excel.
In Excel go to the Data tab in the ribbon and select Get Data and Launch Power Query Editor

When the Editor opens select Manage Parameters

Click On New and create the following
| Name | Required | Type | Suggested Value | Current Value |
|---|---|---|---|---|
| User_ID | Yes | Text | Any Value | Your Unique User ID from ABS |
| Bearer_Key | Yes | Text | Any Value | Your API key from ABS |
| ItemsPerPage | Yes | Any | Any Value | 1000000 |
| ABS_Server | Yes | Any | Any Value | Your ABS Server address (do not include https://) |
Once done click OK.
Now select New Source

Other Sources then Blank Query

Click on Advanced Editor

In the screen that appears delete the text that appears and enter the following
let
// Get the values of parameters
User_ID = Text.From(#"User_ID"),
Bearer_Key = Text.From(#"Bearer_Key"),
ItemsPerPage = Text.From(#"ItemsPerPage"),
ABS_Server = Text.From(#"ABS_Server"),
// Construct the API URL
apiUrl = "https://" & ABS_Server & "/api/users/" & User_ID & "/listening-sessions?itemsPerPage=" & ItemsPerPage,
// Set the headers with the Bearer Token
headers = [#"Authorization" = "Bearer " & Bearer_Key],
// Make the GET request
response = Web.Contents(apiUrl, [Headers=headers]),
// Convert the response to JSON
jsonResponse = Json.Document(response),
// Extract 'sessions' field
sessions = jsonResponse[sessions],
// Convert 'sessions' list to a table
sessionsTable = Table.FromList(sessions, Splitter.SplitByNothing()),
// Expand the record fields
expandedFields = Table.ExpandRecordColumn(sessionsTable, "Column1", {"id", "userId", "libraryId", "libraryItemId", "bookId", "episodeId", "mediaType", "mediaMetadata", "chapters", "displayTitle",
"displayAuthor", "coverPath", "duration", "playMethod", "mediaPlayer", "deviceInfo", "serverVersion", "date", "dayOfWeek", "timeListening", "startTime", "currentTime", "startedAt", "updatedAt"}),
// Expand the 'mediaMetadata' record
expandedMediaMetadata = Table.ExpandRecordColumn(expandedFields, "mediaMetadata", {"title", "subtitle", "author", "releaseDate"}),
// Convert duration to HH:MM:SS format
durationFormatted = Table.AddColumn(expandedMediaMetadata, "Duration (HH:MM:SS)", each
let
totalSeconds = [duration],
hours = Number.RoundDown(totalSeconds / 3600),
remainingSeconds = totalSeconds - hours * 3600,
minutes = Number.RoundDown(remainingSeconds / 60),
seconds = Number.RoundDown(remainingSeconds - minutes * 60),
formattedDuration = Text.From(hours) & ":" & Text.From(minutes) & ":" & Text.From(seconds)
in
formattedDuration
),
// Convert date to DateTime type first, and then to UK format
dateFormatted = Table.TransformColumns(durationFormatted, {{"date", each DateTime.FromText(_, "en-GB"), type datetime}}),
dateFormattedUK = Table.TransformColumns(dateFormatted, {{"date", each DateTime.ToText(_, "dd/MM/yyyy"), type text}}),
// Select the desired fields
selectedFields = Table.SelectColumns(dateFormattedUK, {"mediaType", "title", "subtitle","author", "displayTitle", "displayAuthor", "Duration (HH:MM:SS)", "date", "dayOfWeek", "timeListening"}),
// Remove wrong column
#"Removed Columns" = Table.RemoveColumns(selectedFields,{"author"}),
//Rename Columns to make it easier
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"displayTitle", "episode Title or Book Title"}, {"displayAuthor", "Author"}, {"date", "Date Listened"}, {"Duration (HH:MM:SS)", "Duration of Title (HH:MM:SS)"}, {"timeListening", "Listening Time (Seconds)"}}),
// Convert Listening Time to HH:MM:SS format
listeningTimeFormatted = Table.AddColumn(#"Renamed Columns", "Listening Time (HH:MM:SS)", each
let
totalSeconds = [#"Listening Time (Seconds)"],
hours = Number.RoundDown(totalSeconds / 3600),
remainingSeconds = totalSeconds - hours * 3600,
minutes = Number.RoundDown(remainingSeconds / 60),
seconds = Number.Round(remainingSeconds - minutes * 60, 0),
formattedListeningTime = Text.From(hours) & ":" & Text.From(minutes) & ":" & Text.From(seconds)
in
formattedListeningTime
),
//Convert Date Listened to Date Format
#"Changed Type" = Table.TransformColumnTypes(listeningTimeFormatted,{{"Date Listened", type date}, {"Duration of Title (HH:MM:SS)", type time}, {"Listening Time (HH:MM:SS)", type time}})
in
#"Changed Type"
Once done click on Close and Load


