diff --git a/supporting-blog-content/spotify-to-elasticsearch/.flake8 b/supporting-blog-content/spotify-to-elasticsearch/.flake8 new file mode 100644 index 00000000..980619ff --- /dev/null +++ b/supporting-blog-content/spotify-to-elasticsearch/.flake8 @@ -0,0 +1,3 @@ +[flake8] + +max-line-length = 180 \ No newline at end of file diff --git a/supporting-blog-content/spotify-to-elasticsearch/.pylintrc b/supporting-blog-content/spotify-to-elasticsearch/.pylintrc new file mode 100644 index 00000000..959062e8 --- /dev/null +++ b/supporting-blog-content/spotify-to-elasticsearch/.pylintrc @@ -0,0 +1,4 @@ +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=180 \ No newline at end of file diff --git a/supporting-blog-content/spotify-to-elasticsearch/README.MD b/supporting-blog-content/spotify-to-elasticsearch/README.MD new file mode 100644 index 00000000..236be190 --- /dev/null +++ b/supporting-blog-content/spotify-to-elasticsearch/README.MD @@ -0,0 +1,147 @@ +# Spotify to Elasticsearch + +What does it do? + +- It works with the spotify API to retrieve metadata. +- It imports your Spotify Privacy export. +- It sends all your songs to an Elasticsearch Cluster for analyzing. + +## Requirements + +It uses the [Spotipy](https://spotipy.readthedocs.io/en/2.25.0/) library to connect and interact with Spotify API. Therefore you need to create your own Spotify Developer Account. + +To minimize the strain on the Spotify API, we are creating a local `metadata_cache.json` file that stores all the unique songs ID + metadata retrieved. If you listen to a song twice, we will only ask the Spotify API once for the metadata. + +This was tested and written with Python 3.13. + +### Spotify data export + +This can take up to 30 days. You will get a mail as soon as the download is ready. + +1. Go to [Spotify Privacy](https://www.spotify.com/account/privacy/) +2. Scroll down and select: `Extended Streaming History` it is the right top one. +3. Click in the bottom `request data` +4. You will get a mail to validate that you want this data. +5. Wait until you receive a mail that your data is ready for download. + +### Spotify developer account + +We need a Spotify developer account otherwise we are not allowed to ask the API. + +1. Go to [Spotify Developer](http://developer.spotify.com/) +2. In the top right corner `Log In` +3. Log In with your normal Spotify Account +4. In the top right corner, where the `Log In` button was, click on your name and select `Dashboard` +5. Click on `Create App` +6. Give it an App name like `Elasticsearch Wrapped` +7. Give it a description like `Reading metadata about songs for Elasticsearch` +8. Redirect URIs put `http://localhost:9100` +9. Under: `Which API/SDKs are you planning to use?` + 1. Select `Web API` +10. Accept the terms and conditions +11. In the top right corner select `Settings` +12. Copy `client ID` and `client secret`. (We pass this as parameters when we run the script) + +### Elastic API Key & Elasticsearch URL + +1. Log into your Elastic cluster [Elastic Cloud](https://cloud.elastic.co) and either do a serverless project or hosted deployment. (It works with On Premise or any other form of deployment as well) +2. Serverless, you would create an `Observability Project` + 1. Go to manage, click in the top right corner on: `Connection details` and mark down the `Elasticsearch URL`. Should look something like this `https://-number.es.` + 2. API Key (Please note that this will give the API key the same permissions you have, easiest and quickest) + 1. UI: + 1. Project Settings => Management => API keys => Create API Key => `spotify` as name. Copy the `endcoded` value. It will only be shown once. + 2. Developer Tools: + +```json +POST _security/api_key +{ + "name": "spotify" +} +``` + +3. Hosted deployment: + 1. Go onto your deployment, or create a new one. + 2. Press the `copy endpoint` button for Elasticsearch. + 3. API Key: + +```json +POST _security/api_key +{ + "name": "spotify" +} +``` + +> Note: If you want more fine grained control, this is the minimum the application needs: + +
+ API Request + +```json +POST _security/api_key +{ + "name": "spotify", + "role_descriptors": { + "spotify_history": { + "cluster": [ + "monitor", + "manage_ingest_pipelines" + ], + "indices": [ + { + "names": [ + "spotify-history" + ], + "privileges": [ + "all" + ], + "field_security": { + "grant": [ + "*" + ], + "except": [] + }, + "allow_restricted_indices": false + } + ], + "applications": [], + "run_as": [], + "metadata": {}, + "transient_metadata": { + "enabled": true + } + } + } +} +``` + +
+ +## Executing + +1. Place the extracted files from the zip folder into the `to_read` folder. It needs to be the JSON files directly and not the zip. +1. Execute `pip install -r requirements.txt` and install all the dependencies. +1. Just run in your favorite shell and it will execute and find all the files in the `to_read` folder. + +```shell +python3 python/main.py \ +--es-url "https://spotify.es....:443" \ +--es-api-key "WFdNcE1KTU...==" \ +--spotify-client-id "f972762..." \ +--spotify-client-secret "74bcf5196b..." \ +--user-name "philipp" +``` + +The `--user-name` is optional but helpful if you index the data of your friends and family as well. The field in Elastic is then called `user` + +## Caveats + +- It only works with songs. No support for videos, podcasts or anything else yet. +- If you restart it at any point, it will just index everything again and overwrite what is in there. It moves the finished file to the `processed` folder. Once a file is fully done, it won't be touched again unless you move it to the `to_read` folder again. +- The way I set the `_id` means that you can only listen to one artist per second. +- It will log the track for which it cannot find any metadata. That could be due to spotify changing the track ID, because it removed the album the track was part of. + +## Kibana Dashboard + +There is a prebuild dashboard available, you can import that through the saved objects in Kibana. It was built on 8.17. + +![Kibana Dashboard Preview](kibana/dashboard.jpeg) diff --git a/supporting-blog-content/spotify-to-elasticsearch/kibana/dashboard.jpeg b/supporting-blog-content/spotify-to-elasticsearch/kibana/dashboard.jpeg new file mode 100644 index 00000000..cb8b6fff Binary files /dev/null and b/supporting-blog-content/spotify-to-elasticsearch/kibana/dashboard.jpeg differ diff --git a/supporting-blog-content/spotify-to-elasticsearch/kibana/dashboard.ndjson b/supporting-blog-content/spotify-to-elasticsearch/kibana/dashboard.ndjson new file mode 100644 index 00000000..8327b029 --- /dev/null +++ b/supporting-blog-content/spotify-to-elasticsearch/kibana/dashboard.ndjson @@ -0,0 +1,3 @@ +{"attributes":{"allowHidden":false,"fieldAttrs":"{\"duration\":{\"count\":0},\"listened_to_ms\":{\"count\":0},\"listened_to_pct\":{\"count\":0},\"spotify_metadata.duration_ms\":{\"count\":0}}","fieldFormatMap":"{\"duration\":{\"id\":\"duration\",\"params\":{\"parsedUrl\":{\"origin\":\"https://reproducable-bug-hopefully-kibana-vanishing.kb.us-central1.gcp.cloud.es.io\",\"pathname\":\"/app/management/kibana/dataViews/dataView/811b42b9e0cbc4f2144d8c0c904642595b73ac05aba09d1192bcb3a0a631f3b2\",\"basePath\":\"\"},\"inputFormat\":\"milliseconds\",\"outputFormat\":\"humanizePrecise\",\"outputPrecision\":2,\"includeSpaceWithSuffix\":true}},\"listened_to_ms\":{\"id\":\"duration\",\"params\":{\"parsedUrl\":{\"origin\":\"https://reproducable-bug-hopefully-kibana-vanishing.kb.us-central1.gcp.cloud.es.io\",\"pathname\":\"/app/management/kibana/dataViews/dataView/811b42b9e0cbc4f2144d8c0c904642595b73ac05aba09d1192bcb3a0a631f3b2\",\"basePath\":\"\"},\"inputFormat\":\"milliseconds\",\"outputFormat\":\"humanizePrecise\",\"outputPrecision\":2,\"includeSpaceWithSuffix\":true}},\"listened_to_pct\":{\"id\":\"percent\",\"params\":{}},\"spotify_metadata.duration_ms\":{\"id\":\"duration\",\"params\":{\"parsedUrl\":{\"origin\":\"https://reproducable-bug-hopefully-kibana-vanishing.kb.us-central1.gcp.cloud.es.io\",\"pathname\":\"/app/management/kibana/dataViews/dataView/811b42b9e0cbc4f2144d8c0c904642595b73ac05aba09d1192bcb3a0a631f3b2\",\"basePath\":\"\"},\"inputFormat\":\"milliseconds\",\"outputFormat\":\"humanizePrecise\",\"outputPrecision\":2,\"includeSpaceWithSuffix\":true}}}","fields":"[]","name":"Spotify History","runtimeFieldMap":"{}","sourceFilters":"[]","timeFieldName":"@timestamp","title":"spotify-history*"},"coreMigrationVersion":"8.8.0","created_at":"2025-01-13T09:54:48.076Z","created_by":"u_H8wCOln3L1V7i_dxli1nxpWKh5fdCOVL1o1TOwqJW7I_0","id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2025-01-13T09:54:48.076Z","updated_by":"u_H8wCOln3L1V7i_dxli1nxpWKh5fdCOVL1o1TOwqJW7I_0","version":"WzI1MTg1LDYwXQ=="} +{"attributes":{"controlGroupInput":{"chainingSystem":"HIERARCHICAL","controlStyle":"oneLine","ignoreParentSettingsJSON":"{\"ignoreFilters\":false,\"ignoreQuery\":false,\"ignoreTimerange\":false,\"ignoreValidations\":false}","panelsJSON":"{\"4e752be6-45d8-4c21-ad1a-b3b624954e94\":{\"type\":\"optionsListControl\",\"order\":0,\"grow\":true,\"width\":\"medium\",\"explicitInput\":{\"id\":\"4e752be6-45d8-4c21-ad1a-b3b624954e94\",\"fieldName\":\"artist\",\"title\":\"Artist\",\"grow\":true,\"width\":\"medium\",\"searchTechnique\":\"wildcard\",\"enhancements\":{}}},\"3bb18989-7140-474d-bd8b-699027435af4\":{\"type\":\"optionsListControl\",\"order\":1,\"grow\":true,\"width\":\"medium\",\"explicitInput\":{\"id\":\"3bb18989-7140-474d-bd8b-699027435af4\",\"fieldName\":\"title\",\"title\":\"Title\",\"grow\":true,\"width\":\"medium\",\"searchTechnique\":\"wildcard\",\"enhancements\":{}}},\"13f7c240-f28f-4d21-be79-f98673895ff5\":{\"type\":\"optionsListControl\",\"order\":2,\"grow\":true,\"width\":\"medium\",\"explicitInput\":{\"id\":\"13f7c240-f28f-4d21-be79-f98673895ff5\",\"fieldName\":\"album\",\"title\":\"Album\",\"grow\":true,\"width\":\"medium\",\"searchTechnique\":\"wildcard\",\"enhancements\":{}}},\"610654e8-a14a-41ea-82a2-56532dd21d3c\":{\"type\":\"optionsListControl\",\"order\":3,\"grow\":true,\"width\":\"medium\",\"explicitInput\":{\"id\":\"610654e8-a14a-41ea-82a2-56532dd21d3c\",\"fieldName\":\"user\",\"title\":\"user\",\"grow\":true,\"width\":\"medium\",\"searchTechnique\":\"wildcard\",\"enhancements\":{}}},\"81c47b37-60f4-4377-8d41-862a67914b59\":{\"type\":\"timeSlider\",\"order\":4,\"grow\":true,\"width\":\"large\",\"explicitInput\":{\"id\":\"81c47b37-60f4-4377-8d41-862a67914b59\",\"title\":\"Time slider\",\"enhancements\":{}}}}","showApplySelections":false},"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":34,\"h\":8,\"i\":\"82c8f79a-61c9-4ca9-b250-516100d6d17f\"},\"panelIndex\":\"82c8f79a-61c9-4ca9-b250-516100d6d17f\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-2ac092a4-47dd-4b69-927b-09cdd4ff0edf\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"Linear\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"2ac092a4-47dd-4b69-927b-09cdd4ff0edf\",\"accessors\":[\"7329e098-2585-40ff-8257-49caafb28980\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}},\"xAccessor\":\"082e1383-19c9-4127-9e24-eadc30ada958\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"2ac092a4-47dd-4b69-927b-09cdd4ff0edf\":{\"columns\":{\"082e1383-19c9-4127-9e24-eadc30ada958\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"7329e098-2585-40ff-8257-49caafb28980\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"082e1383-19c9-4127-9e24-eadc30ada958\",\"7329e098-2585-40ff-8257-49caafb28980\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":34,\"y\":0,\"w\":7,\"h\":4,\"i\":\"5422346c-4659-4cfb-9807-29740044fbf7\"},\"panelIndex\":\"5422346c-4659-4cfb-9807-29740044fbf7\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"layerType\":\"data\",\"metricAccessor\":\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\":{\"columns\":{\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\":{\"label\":\"Unique count of title\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"title\",\"isBucketed\":false,\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":41,\"y\":0,\"w\":7,\"h\":4,\"i\":\"7b9d6763-33ab-4220-96a0-708ab7d130b3\"},\"panelIndex\":\"7b9d6763-33ab-4220-96a0-708ab7d130b3\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"layerType\":\"data\",\"metricAccessor\":\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\":{\"columns\":{\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\":{\"label\":\"Total listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":0,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}}},\"customLabel\":true}},\"columnOrder\":[\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":34,\"y\":4,\"w\":7,\"h\":4,\"i\":\"c23aac8a-05f2-4f53-b997-3fe93ad23ab5\"},\"panelIndex\":\"c23aac8a-05f2-4f53-b997-3fe93ad23ab5\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"layerType\":\"data\",\"metricAccessor\":\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\":{\"columns\":{\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\":{\"label\":\"Unique count of album\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"album\",\"isBucketed\":false,\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":8,\"w\":48,\"h\":6,\"i\":\"b988f16e-e341-475b-9403-e8006bb4837d\"},\"panelIndex\":\"b988f16e-e341-475b-9403-e8006bb4837d\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-362b0a89-330b-4c23-8eea-c8cccbb7211b\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"362b0a89-330b-4c23-8eea-c8cccbb7211b\",\"layerType\":\"data\",\"breakdownByAccessor\":\"e333b568-83bb-49f8-9bdc-7231210a0893\",\"metricAccessor\":\"8d75c410-119b-40a5-ae64-3da62af06090\",\"maxCols\":9},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"362b0a89-330b-4c23-8eea-c8cccbb7211b\":{\"columns\":{\"e333b568-83bb-49f8-9bdc-7231210a0893\":{\"label\":\"listened_to_pct\",\"dataType\":\"string\",\"operationType\":\"range\",\"sourceField\":\"listened_to_pct\",\"isBucketed\":true,\"scale\":\"ordinal\",\"params\":{\"type\":\"range\",\"ranges\":[{\"from\":0,\"to\":0.05,\"label\":\"\"},{\"from\":0.05,\"to\":0.1,\"label\":\"\"},{\"from\":0.1,\"to\":0.2,\"label\":\"\"},{\"from\":0.2,\"to\":0.4,\"label\":\"\"},{\"from\":0.4,\"to\":0.6,\"label\":\"\"},{\"from\":0.6,\"to\":0.8,\"label\":\"\"},{\"from\":0.8,\"to\":0.9,\"label\":\"\"},{\"from\":0.9,\"to\":1,\"label\":\"\"}],\"maxBars\":499.5,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}},\"parentFormat\":{\"id\":\"range\",\"params\":{\"template\":\"arrow_right\",\"replaceInfinity\":true}}}},\"8d75c410-119b-40a5-ae64-3da62af06090\":{\"label\":\"Count of songs\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"e333b568-83bb-49f8-9bdc-7231210a0893\",\"8d75c410-119b-40a5-ae64-3da62af06090\"],\"incompleteColumns\":{},\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}},\"title\":\"How far to completion do you listen?\"},{\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":14,\"w\":48,\"h\":5,\"i\":\"af821967-ed3d-44ef-98dc-06798fef7f28\"},\"panelIndex\":\"af821967-ed3d-44ef-98dc-06798fef7f28\",\"embeddableConfig\":{\"enhancements\":{\"dynamicActions\":{\"events\":[]}},\"savedVis\":{\"id\":\"\",\"title\":\"\",\"description\":\"\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"openLinksInNewTab\":false,\"markdown\":\"# Artists\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":19,\"w\":9,\"h\":5,\"i\":\"791d25c7-54b8-4eaa-afa4-99f5331ef582\"},\"panelIndex\":\"791d25c7-54b8-4eaa-afa4-99f5331ef582\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"layerType\":\"data\",\"metricAccessor\":\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\":{\"columns\":{\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\":{\"label\":\"Unique count of artist\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"artist\",\"isBucketed\":false,\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":9,\"y\":19,\"w\":39,\"h\":10,\"i\":\"109d84ac-48cb-4a51-878c-fd6d203bade8\"},\"panelIndex\":\"109d84ac-48cb-4a51-878c-fd6d203bade8\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-226df64c-60f8-4d56-aec3-1ac6f9cc6bf2\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"226df64c-60f8-4d56-aec3-1ac6f9cc6bf2\",\"layerType\":\"data\",\"metricAccessor\":\"65fdf6c5-45b0-4a38-aea8-686e3ac0fdf9\",\"breakdownByAccessor\":\"b8ea8a68-bc0f-4d0c-a623-6e5256b4443e\",\"maxCols\":10},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"226df64c-60f8-4d56-aec3-1ac6f9cc6bf2\":{\"columns\":{\"65fdf6c5-45b0-4a38-aea8-686e3ac0fdf9\":{\"label\":\"Total listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":0,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}}},\"customLabel\":true},\"b8ea8a68-bc0f-4d0c-a623-6e5256b4443e\":{\"label\":\"Top 10 values of artist\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"artist\",\"isBucketed\":true,\"params\":{\"size\":10,\"orderBy\":{\"type\":\"column\",\"columnId\":\"65fdf6c5-45b0-4a38-aea8-686e3ac0fdf9\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true}}},\"columnOrder\":[\"b8ea8a68-bc0f-4d0c-a623-6e5256b4443e\",\"65fdf6c5-45b0-4a38-aea8-686e3ac0fdf9\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":24,\"w\":9,\"h\":5,\"i\":\"933169af-ced5-4845-9531-0ef4ffa394d3\"},\"panelIndex\":\"933169af-ced5-4845-9531-0ef4ffa394d3\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\",\"layerType\":\"data\",\"metricAccessor\":\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\",\"showBar\":false},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ddf00eb3-8a8d-4e30-a683-755d1a5774b2\":{\"columns\":{\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\":{\"label\":\"Median listening completion\",\"dataType\":\"number\",\"operationType\":\"median\",\"sourceField\":\"listened_to_pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}},\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"b4dab2a6-b211-40f6-99d8-589feb9de9b2\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":29,\"w\":23,\"h\":10,\"i\":\"0e963cfc-1d62-4118-8805-ea8ed7855307\"},\"panelIndex\":\"0e963cfc-1d62-4118-8805-ea8ed7855307\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-c9cdc71c-c97f-4c47-914a-d40c13592927\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"title\":\"Empty XY chart\",\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"c9cdc71c-c97f-4c47-914a-d40c13592927\",\"accessors\":[\"c0d7929b-bfd3-43ed-a1a3-f2d65d9f1eb1\"],\"position\":\"top\",\"seriesType\":\"bar_percentage_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}},\"splitAccessor\":\"ce536735-3aa1-409a-8c28-67e67153341a\",\"xAccessor\":\"44bb2594-4473-4a33-9751-8003d8a91f21\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"c9cdc71c-c97f-4c47-914a-d40c13592927\":{\"columns\":{\"ce536735-3aa1-409a-8c28-67e67153341a\":{\"label\":\"Top 25 values of artist\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"artist\",\"isBucketed\":true,\"params\":{\"size\":25,\"orderBy\":{\"type\":\"column\",\"columnId\":\"c0d7929b-bfd3-43ed-a1a3-f2d65d9f1eb1\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true}},\"44bb2594-4473-4a33-9751-8003d8a91f21\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"c0d7929b-bfd3-43ed-a1a3-f2d65d9f1eb1\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"ce536735-3aa1-409a-8c28-67e67153341a\",\"44bb2594-4473-4a33-9751-8003d8a91f21\",\"c0d7929b-bfd3-43ed-a1a3-f2d65d9f1eb1\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}},\"title\":\"Song count per artist over time\"},{\"type\":\"lens\",\"gridData\":{\"x\":23,\"y\":29,\"w\":25,\"h\":10,\"i\":\"4dd44b29-f6e6-4a30-afd0-af8145fb3745\"},\"panelIndex\":\"4dd44b29-f6e6-4a30-afd0-af8145fb3745\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-1d8cffe8-8a25-41d3-99b0-860de1d1783c\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"columns\":[{\"isTransposed\":false,\"columnId\":\"08734724-b6be-4f8e-b5a3-4c0300133b62\"},{\"columnId\":\"333b74b5-7a9c-4172-a592-83fe9134a2d5\",\"isTransposed\":false,\"isMetric\":true}],\"layerId\":\"1d8cffe8-8a25-41d3-99b0-860de1d1783c\",\"layerType\":\"data\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"1d8cffe8-8a25-41d3-99b0-860de1d1783c\":{\"columns\":{\"08734724-b6be-4f8e-b5a3-4c0300133b62\":{\"label\":\"Top 50 values of artist\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"artist\",\"isBucketed\":true,\"params\":{\"size\":50,\"orderBy\":{\"type\":\"column\",\"columnId\":\"333b74b5-7a9c-4172-a592-83fe9134a2d5\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true}},\"333b74b5-7a9c-4172-a592-83fe9134a2d5\":{\"label\":\"Total listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":0,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}}},\"customLabel\":true}},\"columnOrder\":[\"08734724-b6be-4f8e-b5a3-4c0300133b62\",\"333b74b5-7a9c-4172-a592-83fe9134a2d5\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":39,\"w\":23,\"h\":10,\"i\":\"337d1583-2fef-4845-8573-309efd20bda1\"},\"panelIndex\":\"337d1583-2fef-4845-8573-309efd20bda1\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-c9cdc71c-c97f-4c47-914a-d40c13592927\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"title\":\"Empty XY chart\",\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"c9cdc71c-c97f-4c47-914a-d40c13592927\",\"accessors\":[\"c0d7929b-bfd3-43ed-a1a3-f2d65d9f1eb1\"],\"position\":\"top\",\"seriesType\":\"bar_percentage_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}},\"splitAccessor\":\"ce536735-3aa1-409a-8c28-67e67153341a\",\"xAccessor\":\"44bb2594-4473-4a33-9751-8003d8a91f21\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"c9cdc71c-c97f-4c47-914a-d40c13592927\":{\"columns\":{\"ce536735-3aa1-409a-8c28-67e67153341a\":{\"label\":\"Top 25 values of artist\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"artist\",\"isBucketed\":true,\"params\":{\"size\":25,\"orderBy\":{\"type\":\"column\",\"columnId\":\"c0d7929b-bfd3-43ed-a1a3-f2d65d9f1eb1\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true}},\"44bb2594-4473-4a33-9751-8003d8a91f21\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"c0d7929b-bfd3-43ed-a1a3-f2d65d9f1eb1\":{\"label\":\"Listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"ce536735-3aa1-409a-8c28-67e67153341a\",\"44bb2594-4473-4a33-9751-8003d8a91f21\",\"c0d7929b-bfd3-43ed-a1a3-f2d65d9f1eb1\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{},\"description\":\"Opposed to song count per artist, this shows you how much you are listening to a single artist in total listening time compared to other artists.\"},\"title\":\"Total listening time per artists\"},{\"type\":\"lens\",\"gridData\":{\"x\":23,\"y\":39,\"w\":25,\"h\":10,\"i\":\"d2c0ca51-90e4-48e7-a8d6-efcaf997cfc5\"},\"panelIndex\":\"d2c0ca51-90e4-48e7-a8d6-efcaf997cfc5\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-1d8cffe8-8a25-41d3-99b0-860de1d1783c\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"columns\":[{\"isTransposed\":false,\"columnId\":\"08734724-b6be-4f8e-b5a3-4c0300133b62\"},{\"columnId\":\"52783f5d-4fc5-4777-8fc9-6ab2ad11ddf9\",\"isTransposed\":false,\"isMetric\":true},{\"columnId\":\"45e6bbc9-4880-44f3-859a-7100fd8b6ac1\",\"isTransposed\":false,\"isMetric\":true}],\"layerId\":\"1d8cffe8-8a25-41d3-99b0-860de1d1783c\",\"layerType\":\"data\"},\"query\":{\"query\":\"skipped: true \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"1d8cffe8-8a25-41d3-99b0-860de1d1783c\":{\"columns\":{\"08734724-b6be-4f8e-b5a3-4c0300133b62\":{\"label\":\"Top 50 values of artist\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"artist\",\"isBucketed\":true,\"params\":{\"size\":50,\"orderBy\":{\"type\":\"column\",\"columnId\":\"52783f5d-4fc5-4777-8fc9-6ab2ad11ddf9\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true}},\"52783f5d-4fc5-4777-8fc9-6ab2ad11ddf9\":{\"label\":\"Count of songs\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"45e6bbc9-4880-44f3-859a-7100fd8b6ac1\":{\"label\":\"When skip happens\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"listened_to_pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"customLabel\":true}},\"columnOrder\":[\"08734724-b6be-4f8e-b5a3-4c0300133b62\",\"52783f5d-4fc5-4777-8fc9-6ab2ad11ddf9\",\"45e6bbc9-4880-44f3-859a-7100fd8b6ac1\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}},\"title\":\"Most skipped artists\"},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":49,\"w\":48,\"h\":24,\"i\":\"0be066df-ce53-455a-ae92-fca2b961b86f\"},\"panelIndex\":\"0be066df-ce53-455a-ae92-fca2b961b86f\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsPie\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-8f6a4798-6f48-418c-899e-a98be7d76878\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"shape\":\"treemap\",\"layers\":[{\"layerId\":\"8f6a4798-6f48-418c-899e-a98be7d76878\",\"primaryGroups\":[\"e023c08a-376c-40f5-a266-bab9ae257290\",\"22690ceb-4085-4e45-9ad5-c542d30c316c\"],\"metrics\":[\"773e8f8d-f57b-421c-8273-b190f788de84\"],\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"default\",\"nestedLegend\":false,\"layerType\":\"data\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"8f6a4798-6f48-418c-899e-a98be7d76878\":{\"columns\":{\"e023c08a-376c-40f5-a266-bab9ae257290\":{\"label\":\"Artist\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"artist\",\"isBucketed\":true,\"params\":{\"size\":25,\"orderBy\":{\"type\":\"column\",\"columnId\":\"773e8f8d-f57b-421c-8273-b190f788de84\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true},\"customLabel\":true},\"22690ceb-4085-4e45-9ad5-c542d30c316c\":{\"label\":\"Song\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"title\",\"isBucketed\":true,\"params\":{\"size\":10,\"orderBy\":{\"type\":\"column\",\"columnId\":\"773e8f8d-f57b-421c-8273-b190f788de84\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true},\"customLabel\":true},\"773e8f8d-f57b-421c-8273-b190f788de84\":{\"label\":\"Listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"e023c08a-376c-40f5-a266-bab9ae257290\",\"22690ceb-4085-4e45-9ad5-c542d30c316c\",\"773e8f8d-f57b-421c-8273-b190f788de84\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"description\":\"The percentage next to the artist represents the total listening time out of your total listening time. And the percentages inside the artist breakdown represent the amount of time listening to a song from that artist.\",\"enhancements\":{}},\"title\":\"Artist breakdown for top listening time per song\"},{\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":73,\"w\":48,\"h\":5,\"i\":\"ed72ea5e-d18f-4baf-ad18-64fb5c9ecc18\"},\"panelIndex\":\"ed72ea5e-d18f-4baf-ad18-64fb5c9ecc18\",\"embeddableConfig\":{\"savedVis\":{\"id\":\"\",\"title\":\"\",\"description\":\"\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"openLinksInNewTab\":false,\"markdown\":\"# Songs\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":78,\"w\":8,\"h\":5,\"i\":\"7db42c88-f4fc-4f58-99f1-454287b37282\"},\"panelIndex\":\"7db42c88-f4fc-4f58-99f1-454287b37282\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-e842eb72-8c7b-4170-a2b4-c37b4b0a2431\",\"type\":\"index-pattern\"},{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-4399da2b-1594-471f-bcec-1dd7a11e49d1\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"e842eb72-8c7b-4170-a2b4-c37b4b0a2431\",\"layerType\":\"data\",\"showBar\":false,\"trendlineLayerId\":\"4399da2b-1594-471f-bcec-1dd7a11e49d1\",\"trendlineLayerType\":\"metricTrendline\",\"trendlineTimeAccessor\":\"5f8526bf-44a7-4c6d-bdce-4fe1f094ed4b\",\"trendlineMetricAccessor\":\"8ed0e0bb-b8da-4718-b26f-fee6e5aa0604\",\"metricAccessor\":\"3a731d06-c112-45ae-a260-fb685a424212\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"e842eb72-8c7b-4170-a2b4-c37b4b0a2431\":{\"columns\":{\"3a731d06-c112-45ae-a260-fb685a424212\":{\"label\":\"Total songs played\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"3a731d06-c112-45ae-a260-fb685a424212\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{},\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"4399da2b-1594-471f-bcec-1dd7a11e49d1\":{\"linkToLayers\":[\"e842eb72-8c7b-4170-a2b4-c37b4b0a2431\"],\"columns\":{\"5f8526bf-44a7-4c6d-bdce-4fe1f094ed4b\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"8ed0e0bb-b8da-4718-b26f-fee6e5aa0604\":{\"label\":\"Total songs played\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"5f8526bf-44a7-4c6d-bdce-4fe1f094ed4b\",\"8ed0e0bb-b8da-4718-b26f-fee6e5aa0604\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{},\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":8,\"y\":78,\"w\":8,\"h\":5,\"i\":\"65200e1c-db35-4ee6-a709-de9242b7bd6c\"},\"panelIndex\":\"65200e1c-db35-4ee6-a709-de9242b7bd6c\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-e842eb72-8c7b-4170-a2b4-c37b4b0a2431\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"e842eb72-8c7b-4170-a2b4-c37b4b0a2431\",\"layerType\":\"data\",\"showBar\":false,\"trendlineSecondaryMetricAccessor\":\"0e9d2e70-ce44-4d9a-afa0-b035254ef8f8\",\"metricAccessor\":\"3a731d06-c112-45ae-a260-fb685a424212\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"e842eb72-8c7b-4170-a2b4-c37b4b0a2431\":{\"columns\":{\"3a731d06-c112-45ae-a260-fb685a424212\":{\"label\":\"Unique song titles\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"title\",\"isBucketed\":false,\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"3a731d06-c112-45ae-a260-fb685a424212\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{},\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":16,\"y\":78,\"w\":7,\"h\":5,\"i\":\"2373f351-f050-4977-84d8-815209b5a34f\"},\"panelIndex\":\"2373f351-f050-4977-84d8-815209b5a34f\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsPie\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-66ef626a-6553-43f2-a60c-005f24b19f69\"}],\"state\":{\"visualization\":{\"shape\":\"pie\",\"layers\":[{\"layerId\":\"66ef626a-6553-43f2-a60c-005f24b19f69\",\"primaryGroups\":[\"631df4a5-ba9f-4319-b880-3259afd31b27\"],\"metrics\":[\"bf66727b-429f-4e23-b466-f0232875be1f\"],\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"default\",\"nestedLegend\":false,\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}}}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"66ef626a-6553-43f2-a60c-005f24b19f69\":{\"columns\":{\"631df4a5-ba9f-4319-b880-3259afd31b27\":{\"label\":\"Top 5 values of explicit\",\"dataType\":\"boolean\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"explicit\",\"isBucketed\":true,\"params\":{\"size\":5,\"orderBy\":{\"type\":\"column\",\"columnId\":\"bf66727b-429f-4e23-b466-f0232875be1f\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}},\"bf66727b-429f-4e23-b466-f0232875be1f\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"631df4a5-ba9f-4319-b880-3259afd31b27\",\"bf66727b-429f-4e23-b466-f0232875be1f\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}},\"title\":\"Explicit vs Non-Explicit songs\"},{\"type\":\"lens\",\"gridData\":{\"x\":23,\"y\":78,\"w\":25,\"h\":29,\"i\":\"efd76c5a-7dbc-416c-9df2-c0b748099dbd\"},\"panelIndex\":\"efd76c5a-7dbc-416c-9df2-c0b748099dbd\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-9d1ca406-8e88-4e9a-ac79-3d63f535018f\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"columns\":[{\"isTransposed\":false,\"columnId\":\"448b66a4-e4c5-480e-8165-cd34d38a31a7\"},{\"isTransposed\":false,\"columnId\":\"2e697cfa-4383-44cc-b50b-04623fef5afd\"},{\"columnId\":\"fd5361a9-64ef-4904-a667-0ae83e857389\",\"isTransposed\":false,\"isMetric\":true},{\"columnId\":\"e2a9a72b-f72e-412b-bc89-e6f4ef843bf5\",\"isTransposed\":false,\"isMetric\":true}],\"layerId\":\"9d1ca406-8e88-4e9a-ac79-3d63f535018f\",\"layerType\":\"data\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"9d1ca406-8e88-4e9a-ac79-3d63f535018f\":{\"columns\":{\"448b66a4-e4c5-480e-8165-cd34d38a31a7\":{\"label\":\"Top songs\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"title\",\"isBucketed\":true,\"params\":{\"size\":50,\"orderBy\":{\"type\":\"column\",\"columnId\":\"2e697cfa-4383-44cc-b50b-04623fef5afd\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true},\"customLabel\":true},\"2e697cfa-4383-44cc-b50b-04623fef5afd\":{\"label\":\"Count of plays\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"fd5361a9-64ef-4904-a667-0ae83e857389\":{\"label\":\"Average point of listening\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"listened_to_pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}},\"emptyAsNull\":true},\"customLabel\":true},\"e2a9a72b-f72e-412b-bc89-e6f4ef843bf5\":{\"label\":\"Total time listening\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":0,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}},\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"448b66a4-e4c5-480e-8165-cd34d38a31a7\",\"2e697cfa-4383-44cc-b50b-04623fef5afd\",\"fd5361a9-64ef-4904-a667-0ae83e857389\",\"e2a9a72b-f72e-412b-bc89-e6f4ef843bf5\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":83,\"w\":23,\"h\":12,\"i\":\"1ae1ad35-6450-41e7-9065-bb55d3c29573\"},\"panelIndex\":\"1ae1ad35-6450-41e7-9065-bb55d3c29573\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-f6a9abb7-77fe-467a-ab50-603d95468df0\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\",\"legendSize\":\"large\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"Linear\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"f6a9abb7-77fe-467a-ab50-603d95468df0\",\"accessors\":[\"56319201-01cb-4cae-b04c-ef19b8488653\"],\"position\":\"top\",\"seriesType\":\"bar_percentage_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}},\"splitAccessor\":\"61494f43-87f3-48e6-85ce-245bf3c7ef65\",\"xAccessor\":\"84349512-b6b4-470b-94f4-2a908c793db9\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"f6a9abb7-77fe-467a-ab50-603d95468df0\":{\"columns\":{\"56319201-01cb-4cae-b04c-ef19b8488653\":{\"label\":\"Count of songs\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"61494f43-87f3-48e6-85ce-245bf3c7ef65\":{\"label\":\"Top 50 values of title\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"title\",\"isBucketed\":true,\"params\":{\"size\":50,\"orderBy\":{\"type\":\"column\",\"columnId\":\"56319201-01cb-4cae-b04c-ef19b8488653\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true}},\"84349512-b6b4-470b-94f4-2a908c793db9\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}}},\"columnOrder\":[\"61494f43-87f3-48e6-85ce-245bf3c7ef65\",\"84349512-b6b4-470b-94f4-2a908c793db9\",\"56319201-01cb-4cae-b04c-ef19b8488653\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":95,\"w\":23,\"h\":12,\"i\":\"b9a131a2-8a86-4300-9597-bbe6dcf886fa\"},\"panelIndex\":\"b9a131a2-8a86-4300-9597-bbe6dcf886fa\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-f6a9abb7-77fe-467a-ab50-603d95468df0\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"Linear\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"f6a9abb7-77fe-467a-ab50-603d95468df0\",\"accessors\":[\"56319201-01cb-4cae-b04c-ef19b8488653\"],\"position\":\"top\",\"seriesType\":\"bar_percentage_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}},\"splitAccessor\":\"61494f43-87f3-48e6-85ce-245bf3c7ef65\",\"xAccessor\":\"84349512-b6b4-470b-94f4-2a908c793db9\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"f6a9abb7-77fe-467a-ab50-603d95468df0\":{\"columns\":{\"56319201-01cb-4cae-b04c-ef19b8488653\":{\"label\":\"Listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"61494f43-87f3-48e6-85ce-245bf3c7ef65\":{\"label\":\"Top 50 values of title\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"title\",\"isBucketed\":true,\"params\":{\"size\":50,\"orderBy\":{\"type\":\"column\",\"columnId\":\"56319201-01cb-4cae-b04c-ef19b8488653\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true}},\"84349512-b6b4-470b-94f4-2a908c793db9\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}}},\"columnOrder\":[\"61494f43-87f3-48e6-85ce-245bf3c7ef65\",\"84349512-b6b4-470b-94f4-2a908c793db9\",\"56319201-01cb-4cae-b04c-ef19b8488653\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":107,\"w\":48,\"h\":14,\"i\":\"d3b57bb3-0305-48ae-802a-6550be720fed\"},\"panelIndex\":\"d3b57bb3-0305-48ae-802a-6550be720fed\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-9d1ca406-8e88-4e9a-ac79-3d63f535018f\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"columns\":[{\"isTransposed\":false,\"columnId\":\"448b66a4-e4c5-480e-8165-cd34d38a31a7\"},{\"isTransposed\":false,\"columnId\":\"2e697cfa-4383-44cc-b50b-04623fef5afd\"},{\"columnId\":\"e2a9a72b-f72e-412b-bc89-e6f4ef843bf5\",\"isTransposed\":false,\"isMetric\":true},{\"columnId\":\"d39f3e6e-bb15-41e7-b027-d7b5e4ccc180\",\"isTransposed\":true,\"isMetric\":false}],\"layerId\":\"9d1ca406-8e88-4e9a-ac79-3d63f535018f\",\"layerType\":\"data\",\"sorting\":{\"columnId\":\"true---2e697cfa-4383-44cc-b50b-04623fef5afd\",\"direction\":\"desc\"}},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"9d1ca406-8e88-4e9a-ac79-3d63f535018f\":{\"columns\":{\"448b66a4-e4c5-480e-8165-cd34d38a31a7\":{\"label\":\"Top songs\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"title\",\"isBucketed\":true,\"params\":{\"size\":50,\"orderBy\":{\"type\":\"column\",\"columnId\":\"2e697cfa-4383-44cc-b50b-04623fef5afd\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true},\"customLabel\":true},\"2e697cfa-4383-44cc-b50b-04623fef5afd\":{\"label\":\"Count of plays\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"e2a9a72b-f72e-412b-bc89-e6f4ef843bf5\":{\"label\":\"Total time listening\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":0,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}},\"emptyAsNull\":true},\"customLabel\":true},\"d39f3e6e-bb15-41e7-b027-d7b5e4ccc180\":{\"label\":\"Top 3 values of skipped\",\"dataType\":\"boolean\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"skipped\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"column\",\"columnId\":\"2e697cfa-4383-44cc-b50b-04623fef5afd\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}}},\"columnOrder\":[\"d39f3e6e-bb15-41e7-b027-d7b5e4ccc180\",\"448b66a4-e4c5-480e-8165-cd34d38a31a7\",\"2e697cfa-4383-44cc-b50b-04623fef5afd\",\"e2a9a72b-f72e-412b-bc89-e6f4ef843bf5\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{},\"description\":\"False => not skipped\\nTrue => I press forward at some point\"},\"title\":\"Songs that I skip.\"},{\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":121,\"w\":48,\"h\":5,\"i\":\"8e2fbc61-3c22-41bd-ae81-d74408479ab2\"},\"panelIndex\":\"8e2fbc61-3c22-41bd-ae81-d74408479ab2\",\"embeddableConfig\":{\"enhancements\":{\"dynamicActions\":{\"events\":[]}},\"savedVis\":{\"id\":\"\",\"title\":\"\",\"description\":\"\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"openLinksInNewTab\":false,\"markdown\":\"# Listening behaviour\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}}},\"title\":\"\"},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":126,\"w\":48,\"h\":6,\"i\":\"cc405525-f956-48ba-9445-35085db9b86e\"},\"panelIndex\":\"cc405525-f956-48ba-9445-35085db9b86e\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-456adc99-cbe6-4f21-8648-a6131cc094d2\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"456adc99-cbe6-4f21-8648-a6131cc094d2\",\"layerType\":\"data\",\"metricAccessor\":\"9a580650-b033-4267-afb1-892a5d96a4df\",\"breakdownByAccessor\":\"d1a4b999-a076-42ce-b5ca-f765e82c8507\",\"maxCols\":7},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"456adc99-cbe6-4f21-8648-a6131cc094d2\":{\"columns\":{\"d1a4b999-a076-42ce-b5ca-f765e82c8507\":{\"label\":\"Day\",\"dataType\":\"string\",\"operationType\":\"filters\",\"scale\":\"ordinal\",\"isBucketed\":true,\"params\":{\"filters\":[{\"label\":\"Monday\",\"input\":{\"query\":\"\\\"dayOfWeek\\\" : Monday\",\"language\":\"kuery\"}},{\"input\":{\"query\":\"dayOfWeek: \\\"Tuesday\\\" \",\"language\":\"kuery\"},\"label\":\"Tuesday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Wednesday\\\" \",\"language\":\"kuery\"},\"label\":\"Wednesday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Thursday\\\" \",\"language\":\"kuery\"},\"label\":\"Thursday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Friday\\\" \",\"language\":\"kuery\"},\"label\":\"Friday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Saturday\\\" \",\"language\":\"kuery\"},\"label\":\"Saturday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Sunday\\\" \",\"language\":\"kuery\"},\"label\":\"Sunday\"}]},\"customLabel\":true},\"9a580650-b033-4267-afb1-892a5d96a4df\":{\"label\":\"Songs played\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"d1a4b999-a076-42ce-b5ca-f765e82c8507\",\"9a580650-b033-4267-afb1-892a5d96a4df\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":132,\"w\":23,\"h\":27,\"i\":\"3902bd15-681b-4aca-9ca9-12b74863027d\"},\"panelIndex\":\"3902bd15-681b-4aca-9ca9-12b74863027d\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsHeatmap\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-456adc99-cbe6-4f21-8648-a6131cc094d2\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"shape\":\"heatmap\",\"layerId\":\"456adc99-cbe6-4f21-8648-a6131cc094d2\",\"layerType\":\"data\",\"legend\":{\"isVisible\":false,\"position\":\"right\",\"type\":\"heatmap_legend\"},\"gridConfig\":{\"type\":\"heatmap_grid\",\"isCellLabelVisible\":false,\"isYAxisLabelVisible\":true,\"isXAxisLabelVisible\":true,\"isYAxisTitleVisible\":true,\"isXAxisTitleVisible\":false},\"valueAccessor\":\"9a580650-b033-4267-afb1-892a5d96a4df\",\"xAccessor\":\"d1a4b999-a076-42ce-b5ca-f765e82c8507\",\"yAccessor\":\"6a115b0b-f0a8-44ed-9368-dec9c0e12887\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"456adc99-cbe6-4f21-8648-a6131cc094d2\":{\"columns\":{\"d1a4b999-a076-42ce-b5ca-f765e82c8507\":{\"label\":\"Day\",\"dataType\":\"string\",\"operationType\":\"filters\",\"scale\":\"ordinal\",\"isBucketed\":true,\"params\":{\"filters\":[{\"label\":\"Monday\",\"input\":{\"query\":\"\\\"dayOfWeek\\\" : Monday\",\"language\":\"kuery\"}},{\"input\":{\"query\":\"dayOfWeek: \\\"Tuesday\\\" \",\"language\":\"kuery\"},\"label\":\"Tuesday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Wednesday\\\" \",\"language\":\"kuery\"},\"label\":\"Wednesday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Thursday\\\" \",\"language\":\"kuery\"},\"label\":\"Thursday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Friday\\\" \",\"language\":\"kuery\"},\"label\":\"Friday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Saturday\\\" \",\"language\":\"kuery\"},\"label\":\"Saturday\"},{\"input\":{\"query\":\"dayOfWeek: \\\"Sunday\\\" \",\"language\":\"kuery\"},\"label\":\"Sunday\"}]},\"customLabel\":true},\"9a580650-b033-4267-afb1-892a5d96a4df\":{\"label\":\"Songs played\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"6a115b0b-f0a8-44ed-9368-dec9c0e12887\":{\"label\":\"Hour of the day\",\"dataType\":\"number\",\"operationType\":\"range\",\"sourceField\":\"hourOfDay\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"includeEmptyRows\":true,\"type\":\"histogram\",\"ranges\":[{\"from\":0,\"to\":1000,\"label\":\"\"}],\"maxBars\":\"auto\"},\"customLabel\":true}},\"columnOrder\":[\"d1a4b999-a076-42ce-b5ca-f765e82c8507\",\"6a115b0b-f0a8-44ed-9368-dec9c0e12887\",\"9a580650-b033-4267-afb1-892a5d96a4df\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":23,\"y\":132,\"w\":25,\"h\":14,\"i\":\"c6512dbf-7764-4300-b96a-8304c2966d71\"},\"panelIndex\":\"c6512dbf-7764-4300-b96a-8304c2966d71\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-fe348419-babd-45f3-bfd9-87f1c262ebdc\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"Linear\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"fe348419-babd-45f3-bfd9-87f1c262ebdc\",\"accessors\":[\"4600c99e-2aca-452b-a728-14bb6d81539e\"],\"position\":\"top\",\"seriesType\":\"bar_percentage_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}},\"xAccessor\":\"a4f297b3-d1b1-4396-a04c-effb2e178753\",\"splitAccessor\":\"d4a6b130-561c-477a-b237-5ff9d5776bcd\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"fe348419-babd-45f3-bfd9-87f1c262ebdc\":{\"columns\":{\"a4f297b3-d1b1-4396-a04c-effb2e178753\":{\"label\":\"Hour of day\",\"dataType\":\"number\",\"operationType\":\"range\",\"sourceField\":\"hourOfDay\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"includeEmptyRows\":true,\"type\":\"histogram\",\"ranges\":[{\"from\":0,\"to\":1000,\"label\":\"\"}],\"maxBars\":1000},\"customLabel\":true},\"d4a6b130-561c-477a-b237-5ff9d5776bcd\":{\"label\":\"Filters\",\"dataType\":\"string\",\"operationType\":\"filters\",\"scale\":\"ordinal\",\"isBucketed\":true,\"params\":{\"filters\":[{\"label\":\"Skipped\",\"input\":{\"query\":\"listened_to_pct < 1\",\"language\":\"kuery\"}},{\"input\":{\"query\":\"listened_to_pct >= 1\",\"language\":\"kuery\"},\"label\":\"Not skipped\"}]}},\"4600c99e-2aca-452b-a728-14bb6d81539e\":{\"label\":\"Count of songs\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"d4a6b130-561c-477a-b237-5ff9d5776bcd\",\"a4f297b3-d1b1-4396-a04c-effb2e178753\",\"4600c99e-2aca-452b-a728-14bb6d81539e\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}},\"title\":\"When do I skip to the next song and when do I finish listening?\"},{\"type\":\"lens\",\"gridData\":{\"x\":23,\"y\":146,\"w\":25,\"h\":13,\"i\":\"94b394f9-8b0f-437b-abfd-c6d9289e7ba8\"},\"panelIndex\":\"94b394f9-8b0f-437b-abfd-c6d9289e7ba8\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Count of songs & month of (empty)\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"6a9ea98762d7829a53a6330401f0f87fedaa6d22b2f290bf8a010bba4f237023\",\"name\":\"textBasedLanguages-datasource-layer-daaf7ae0-5566-4c14-97df-6df0fdbe6567\"}],\"state\":{\"datasourceStates\":{\"textBased\":{\"layers\":{\"daaf7ae0-5566-4c14-97df-6df0fdbe6567\":{\"index\":\"6a9ea98762d7829a53a6330401f0f87fedaa6d22b2f290bf8a010bba4f237023\",\"query\":{\"esql\":\"FROM spotify-history\\n| eval month=DATE_EXTRACT(\\\"MONTH_OF_YEAR\\\", @timestamp)\\n| stats `Count of songs`=count() by month\\n\"},\"columns\":[{\"columnId\":\"Count of songs\",\"fieldName\":\"Count of songs\",\"meta\":{\"type\":\"number\",\"esType\":\"long\"},\"inMetricDimension\":true},{\"columnId\":\"9a0b031d-be3d-481d-b344-6d9e59a5ae26\",\"fieldName\":\"month\",\"meta\":{\"type\":\"number\",\"esType\":\"long\"}}],\"timeField\":\"@timestamp\",\"allColumns\":[{\"columnId\":\"Count of songs\",\"fieldName\":\"Count of songs\",\"meta\":{\"type\":\"number\",\"esType\":\"long\"},\"inMetricDimension\":true},{\"columnId\":\"month\",\"fieldName\":\"month\",\"meta\":{\"type\":\"number\",\"esType\":\"long\"},\"inMetricDimension\":true}]}},\"indexPatternRefs\":[{\"id\":\"6a9ea98762d7829a53a6330401f0f87fedaa6d22b2f290bf8a010bba4f237023\",\"title\":\"spotify-history\",\"timeField\":\"@timestamp\"}]}},\"filters\":[],\"query\":{\"esql\":\"FROM spotify-history\\n| eval month=DATE_EXTRACT(\\\"MONTH_OF_YEAR\\\", @timestamp)\\n| stats `Count of songs`=count() by month\\n\"},\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"daaf7ae0-5566-4c14-97df-6df0fdbe6567\",\"seriesType\":\"bar_stacked\",\"xAccessor\":\"9a0b031d-be3d-481d-b344-6d9e59a5ae26\",\"accessors\":[\"Count of songs\"],\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}}}]},\"adHocDataViews\":{\"6a9ea98762d7829a53a6330401f0f87fedaa6d22b2f290bf8a010bba4f237023\":{\"id\":\"6a9ea98762d7829a53a6330401f0f87fedaa6d22b2f290bf8a010bba4f237023\",\"title\":\"spotify-history\",\"timeFieldName\":\"@timestamp\",\"sourceFilters\":[],\"type\":\"esql\",\"fieldFormats\":{},\"runtimeFieldMap\":{},\"allowNoIndex\":false,\"name\":\"spotify-history\",\"allowHidden\":false}}},\"visualizationType\":\"lnsXY\",\"type\":\"lens\"},\"disabledActions\":[\"OPEN_FLYOUT_ADD_DRILLDOWN\"],\"enhancements\":{}},\"title\":\"Monthly breakdown of song count\"},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":159,\"w\":23,\"h\":12,\"i\":\"57a63464-6b4e-4875-9f88-8b76ecee1bd9\"},\"panelIndex\":\"57a63464-6b4e-4875-9f88-8b76ecee1bd9\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-acdb25a8-14c3-47cc-8924-601e5dda930c\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"Linear\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"acdb25a8-14c3-47cc-8924-601e5dda930c\",\"accessors\":[\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9b\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"colorMapping\":{\"assignments\":[],\"specialAssignments\":[{\"rule\":{\"type\":\"other\"},\"color\":{\"type\":\"loop\"},\"touched\":false}],\"paletteId\":\"eui_amsterdam_color_blind\",\"colorMode\":{\"type\":\"categorical\"}},\"xAccessor\":\"5aaac424-e0d6-418f-9f9d-f805764680dd\"}],\"yLeftExtent\":{\"mode\":\"custom\",\"upperBound\":1,\"lowerBound\":0}},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"acdb25a8-14c3-47cc-8924-601e5dda930c\":{\"columns\":{\"5aaac424-e0d6-418f-9f9d-f805764680dd\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9bX0\":{\"label\":\"Part of median(spotify_metadata.popularity)/100\",\"dataType\":\"number\",\"operationType\":\"median\",\"sourceField\":\"spotify_metadata.popularity\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9bX1\":{\"label\":\"Part of median(spotify_metadata.popularity)/100\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9bX0\",100],\"location\":{\"min\":0,\"max\":39},\"text\":\"median(spotify_metadata.popularity)/100\"}},\"references\":[\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9bX0\"],\"customLabel\":true},\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9b\":{\"label\":\"Median track popularity from Spotify\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"median(spotify_metadata.popularity)/100\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9bX1\"],\"customLabel\":true}},\"columnOrder\":[\"5aaac424-e0d6-418f-9f9d-f805764680dd\",\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9b\",\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9bX0\",\"420c1c44-c653-4cf6-99a5-b9af4ac4ea9bX1\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}},\"title\":\"Am I listening to what Spotify thinks is popular?\"},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":171,\"w\":23,\"h\":15,\"i\":\"fe912a88-2cc7-4943-a25d-4ba8ef8ac13d\"},\"panelIndex\":\"fe912a88-2cc7-4943-a25d-4ba8ef8ac13d\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsPie\",\"type\":\"lens\",\"references\":[{\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-f804cd25-0a41-44a6-b068-cbd3e37210d9\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"shape\":\"waffle\",\"layers\":[{\"layerId\":\"f804cd25-0a41-44a6-b068-cbd3e37210d9\",\"primaryGroups\":[\"a5228e99-23e0-4619-8356-8e25bd00ab11\"],\"metrics\":[\"837e1bea-aa97-45f4-ac52-c7509a5b977a\"],\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"default\",\"nestedLegend\":false,\"layerType\":\"data\",\"legendSize\":\"large\",\"truncateLegend\":false}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"f804cd25-0a41-44a6-b068-cbd3e37210d9\":{\"columns\":{\"837e1bea-aa97-45f4-ac52-c7509a5b977a\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}},\"a5228e99-23e0-4619-8356-8e25bd00ab11\":{\"label\":\"spotify_metadata.popularity\",\"dataType\":\"string\",\"operationType\":\"range\",\"sourceField\":\"spotify_metadata.popularity\",\"isBucketed\":true,\"scale\":\"ordinal\",\"params\":{\"type\":\"range\",\"ranges\":[{\"from\":0,\"to\":10,\"label\":\"0% - 10%\"},{\"from\":10,\"to\":20,\"label\":\"10% - 20%\"},{\"from\":20,\"to\":30,\"label\":\"20% - 30%\"},{\"from\":30,\"to\":40,\"label\":\"30% - 40%\"},{\"from\":40,\"to\":50,\"label\":\"40% - 50%\"},{\"from\":50,\"to\":60,\"label\":\"50% - 60%\"},{\"from\":60,\"to\":70,\"label\":\"60% - 70%\"},{\"from\":70,\"to\":80,\"label\":\"70% - 80%\"},{\"from\":80,\"to\":90,\"label\":\"80% - 90%\"},{\"from\":90,\"to\":100,\"label\":\"90% - 100%\"}],\"maxBars\":499.5,\"parentFormat\":{\"id\":\"range\",\"params\":{\"template\":\"arrow_right\",\"replaceInfinity\":true}}}}},\"columnOrder\":[\"a5228e99-23e0-4619-8356-8e25bd00ab11\",\"837e1bea-aa97-45f4-ac52-c7509a5b977a\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}},\"title\":\"Song distribution vs Spotify popularity\"},{\"type\":\"visualization\",\"gridData\":{\"x\":0,\"y\":186,\"w\":48,\"h\":5,\"i\":\"a4c2cb4a-bf0a-4406-9784-9ac2957464ce\"},\"panelIndex\":\"a4c2cb4a-bf0a-4406-9784-9ac2957464ce\",\"embeddableConfig\":{\"savedVis\":{\"id\":\"\",\"title\":\"\",\"description\":\"\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"openLinksInNewTab\":false,\"markdown\":\"# Yearly breakdowns\"},\"uiState\":{},\"data\":{\"aggs\":[],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":191,\"w\":48,\"h\":13,\"i\":\"62b9cb9d-0d87-4ca9-bd16-239177ec7d3b\"},\"panelIndex\":\"62b9cb9d-0d87-4ca9-bd16-239177ec7d3b\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsMetric\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-1394480e-f256-40ed-b322-e60577736d8b\"}],\"state\":{\"visualization\":{\"layerId\":\"1394480e-f256-40ed-b322-e60577736d8b\",\"layerType\":\"data\",\"metricAccessor\":\"92b46c8c-2716-44a4-ab2e-e4c6e21490cc\",\"breakdownByAccessor\":\"b1f472ab-c2d8-429e-8f55-fae66032d395\",\"showBar\":false,\"maxCols\":8},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"1394480e-f256-40ed-b322-e60577736d8b\":{\"columns\":{\"b1f472ab-c2d8-429e-8f55-fae66032d395\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"1y\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"92b46c8c-2716-44a4-ab2e-e4c6e21490cc\":{\"label\":\"Total Listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":1,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}}},\"customLabel\":true}},\"columnOrder\":[\"b1f472ab-c2d8-429e-8f55-fae66032d395\",\"92b46c8c-2716-44a4-ab2e-e4c6e21490cc\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":204,\"w\":24,\"h\":22,\"i\":\"bcc3efdc-229c-4b41-a034-fc8f11c0df7d\"},\"panelIndex\":\"bcc3efdc-229c-4b41-a034-fc8f11c0df7d\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-c0671a9e-8335-4bd7-8a0c-01c93204e1c3\"}],\"state\":{\"visualization\":{\"layerId\":\"c0671a9e-8335-4bd7-8a0c-01c93204e1c3\",\"layerType\":\"data\",\"columns\":[{\"isTransposed\":false,\"columnId\":\"bb4e8ccd-7434-4c3f-b273-bd51ecf190ac\",\"isMetric\":false},{\"columnId\":\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\"},{\"columnId\":\"fd055017-94ca-4dc9-8a70-2099a86bed54\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"c0671a9e-8335-4bd7-8a0c-01c93204e1c3\":{\"columns\":{\"bb4e8ccd-7434-4c3f-b273-bd51ecf190ac\":{\"label\":\"Top Artist\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"artist\",\"isBucketed\":true,\"params\":{\"size\":1,\"orderBy\":{\"type\":\"column\",\"columnId\":\"fd055017-94ca-4dc9-8a70-2099a86bed54\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true},\"customLabel\":true},\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\":{\"label\":\"Year\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"1y\",\"includeEmptyRows\":true,\"dropPartials\":false},\"customLabel\":true},\"fd055017-94ca-4dc9-8a70-2099a86bed54\":{\"label\":\"Total listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":1,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}}},\"customLabel\":true}},\"columnOrder\":[\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\",\"bb4e8ccd-7434-4c3f-b273-bd51ecf190ac\",\"fd055017-94ca-4dc9-8a70-2099a86bed54\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":204,\"w\":24,\"h\":22,\"i\":\"5b42566d-cfcd-4d05-883b-9c1d5f5e0744\"},\"panelIndex\":\"5b42566d-cfcd-4d05-883b-9c1d5f5e0744\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-c0671a9e-8335-4bd7-8a0c-01c93204e1c3\"}],\"state\":{\"visualization\":{\"layerId\":\"c0671a9e-8335-4bd7-8a0c-01c93204e1c3\",\"layerType\":\"data\",\"columns\":[{\"isTransposed\":false,\"columnId\":\"bb4e8ccd-7434-4c3f-b273-bd51ecf190ac\",\"isMetric\":false},{\"columnId\":\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\"},{\"columnId\":\"fd055017-94ca-4dc9-8a70-2099a86bed54\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"c0671a9e-8335-4bd7-8a0c-01c93204e1c3\":{\"columns\":{\"bb4e8ccd-7434-4c3f-b273-bd51ecf190ac\":{\"label\":\"Top Song\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"title\",\"isBucketed\":true,\"params\":{\"size\":1,\"orderBy\":{\"type\":\"column\",\"columnId\":\"fd055017-94ca-4dc9-8a70-2099a86bed54\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"accuracyMode\":true,\"secondaryFields\":[]},\"customLabel\":true},\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\":{\"label\":\"Year\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"1y\",\"includeEmptyRows\":true,\"dropPartials\":false},\"customLabel\":true},\"fd055017-94ca-4dc9-8a70-2099a86bed54\":{\"label\":\"Total listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":1,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}}},\"customLabel\":true}},\"columnOrder\":[\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\",\"bb4e8ccd-7434-4c3f-b273-bd51ecf190ac\",\"fd055017-94ca-4dc9-8a70-2099a86bed54\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":226,\"w\":24,\"h\":24,\"i\":\"e35904ac-37fc-47a0-b7ed-2a18b3ee49a7\"},\"panelIndex\":\"e35904ac-37fc-47a0-b7ed-2a18b3ee49a7\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\",\"name\":\"indexpattern-datasource-layer-c0671a9e-8335-4bd7-8a0c-01c93204e1c3\"}],\"state\":{\"visualization\":{\"layerId\":\"c0671a9e-8335-4bd7-8a0c-01c93204e1c3\",\"layerType\":\"data\",\"columns\":[{\"columnId\":\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\"},{\"columnId\":\"fd055017-94ca-4dc9-8a70-2099a86bed54\"},{\"columnId\":\"44e8b546-2654-4a9c-b06a-887024321266\",\"isTransposed\":false,\"isMetric\":true},{\"columnId\":\"bee4888e-305a-4e53-9188-fdd80fb85729\",\"isTransposed\":false,\"isMetric\":true},{\"columnId\":\"f396d6e2-383b-43f7-8941-d5bee8dc1bce\",\"isTransposed\":false,\"isMetric\":true},{\"columnId\":\"804a34e3-1759-497c-ab58-df93c39e2de2\",\"isTransposed\":false,\"isMetric\":true}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"c0671a9e-8335-4bd7-8a0c-01c93204e1c3\":{\"columns\":{\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\":{\"label\":\"Year\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"1y\",\"includeEmptyRows\":true,\"dropPartials\":false},\"customLabel\":true},\"fd055017-94ca-4dc9-8a70-2099a86bed54\":{\"label\":\"Total listening time\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"listened_to_ms\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"duration\",\"params\":{\"decimals\":1,\"fromUnit\":\"milliseconds\",\"toUnit\":\"humanizePrecise\"}}},\"customLabel\":true},\"44e8b546-2654-4a9c-b06a-887024321266\":{\"label\":\"Unique songs\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"title\",\"isBucketed\":false,\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"bee4888e-305a-4e53-9188-fdd80fb85729\":{\"label\":\"Unique artists\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"artist\",\"isBucketed\":false,\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"f396d6e2-383b-43f7-8941-d5bee8dc1bce\":{\"label\":\"Total songs\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"804a34e3-1759-497c-ab58-df93c39e2de2\":{\"label\":\"Median song completion\",\"dataType\":\"number\",\"operationType\":\"median\",\"sourceField\":\"listened_to_pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"customLabel\":true}},\"columnOrder\":[\"c3116ed3-648f-4caf-8d6d-527ba523a6ac\",\"fd055017-94ca-4dc9-8a70-2099a86bed54\",\"44e8b546-2654-4a9c-b06a-887024321266\",\"bee4888e-305a-4e53-9188-fdd80fb85729\",\"f396d6e2-383b-43f7-8941-d5bee8dc1bce\",\"804a34e3-1759-497c-ab58-df93c39e2de2\"],\"incompleteColumns\":{},\"sampling\":1,\"indexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"}},\"currentIndexPatternId\":\"784d0077-811c-4d9c-8866-7c6e8a031ab1\"},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}}]","refreshInterval":{"pause":true,"value":60000},"timeFrom":"2010-01-01T00:00:00.000Z","timeRestore":true,"timeTo":"now/y","title":"[Blog] Spotify History","version":2},"coreMigrationVersion":"8.8.0","created_at":"2025-01-13T09:54:48.519Z","created_by":"u_H8wCOln3L1V7i_dxli1nxpWKh5fdCOVL1o1TOwqJW7I_0","id":"58f4116d-10e7-4132-8870-8b18eef978d0","managed":false,"references":[{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"82c8f79a-61c9-4ca9-b250-516100d6d17f:indexpattern-datasource-layer-2ac092a4-47dd-4b69-927b-09cdd4ff0edf","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"5422346c-4659-4cfb-9807-29740044fbf7:indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"7b9d6763-33ab-4220-96a0-708ab7d130b3:indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"c23aac8a-05f2-4f53-b997-3fe93ad23ab5:indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"b988f16e-e341-475b-9403-e8006bb4837d:indexpattern-datasource-layer-362b0a89-330b-4c23-8eea-c8cccbb7211b","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"791d25c7-54b8-4eaa-afa4-99f5331ef582:indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"109d84ac-48cb-4a51-878c-fd6d203bade8:indexpattern-datasource-layer-226df64c-60f8-4d56-aec3-1ac6f9cc6bf2","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"933169af-ced5-4845-9531-0ef4ffa394d3:indexpattern-datasource-layer-ddf00eb3-8a8d-4e30-a683-755d1a5774b2","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"0e963cfc-1d62-4118-8805-ea8ed7855307:indexpattern-datasource-layer-c9cdc71c-c97f-4c47-914a-d40c13592927","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"4dd44b29-f6e6-4a30-afd0-af8145fb3745:indexpattern-datasource-layer-1d8cffe8-8a25-41d3-99b0-860de1d1783c","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"337d1583-2fef-4845-8573-309efd20bda1:indexpattern-datasource-layer-c9cdc71c-c97f-4c47-914a-d40c13592927","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"d2c0ca51-90e4-48e7-a8d6-efcaf997cfc5:indexpattern-datasource-layer-1d8cffe8-8a25-41d3-99b0-860de1d1783c","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"0be066df-ce53-455a-ae92-fca2b961b86f:indexpattern-datasource-layer-8f6a4798-6f48-418c-899e-a98be7d76878","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"7db42c88-f4fc-4f58-99f1-454287b37282:indexpattern-datasource-layer-e842eb72-8c7b-4170-a2b4-c37b4b0a2431","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"7db42c88-f4fc-4f58-99f1-454287b37282:indexpattern-datasource-layer-4399da2b-1594-471f-bcec-1dd7a11e49d1","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"65200e1c-db35-4ee6-a709-de9242b7bd6c:indexpattern-datasource-layer-e842eb72-8c7b-4170-a2b4-c37b4b0a2431","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"2373f351-f050-4977-84d8-815209b5a34f:indexpattern-datasource-layer-66ef626a-6553-43f2-a60c-005f24b19f69","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"efd76c5a-7dbc-416c-9df2-c0b748099dbd:indexpattern-datasource-layer-9d1ca406-8e88-4e9a-ac79-3d63f535018f","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"1ae1ad35-6450-41e7-9065-bb55d3c29573:indexpattern-datasource-layer-f6a9abb7-77fe-467a-ab50-603d95468df0","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"b9a131a2-8a86-4300-9597-bbe6dcf886fa:indexpattern-datasource-layer-f6a9abb7-77fe-467a-ab50-603d95468df0","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"d3b57bb3-0305-48ae-802a-6550be720fed:indexpattern-datasource-layer-9d1ca406-8e88-4e9a-ac79-3d63f535018f","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"cc405525-f956-48ba-9445-35085db9b86e:indexpattern-datasource-layer-456adc99-cbe6-4f21-8648-a6131cc094d2","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"3902bd15-681b-4aca-9ca9-12b74863027d:indexpattern-datasource-layer-456adc99-cbe6-4f21-8648-a6131cc094d2","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"c6512dbf-7764-4300-b96a-8304c2966d71:indexpattern-datasource-layer-fe348419-babd-45f3-bfd9-87f1c262ebdc","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"94b394f9-8b0f-437b-abfd-c6d9289e7ba8:textBasedLanguages-datasource-layer-daaf7ae0-5566-4c14-97df-6df0fdbe6567","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"57a63464-6b4e-4875-9f88-8b76ecee1bd9:indexpattern-datasource-layer-acdb25a8-14c3-47cc-8924-601e5dda930c","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"fe912a88-2cc7-4943-a25d-4ba8ef8ac13d:indexpattern-datasource-layer-f804cd25-0a41-44a6-b068-cbd3e37210d9","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"62b9cb9d-0d87-4ca9-bd16-239177ec7d3b:indexpattern-datasource-layer-1394480e-f256-40ed-b322-e60577736d8b","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"bcc3efdc-229c-4b41-a034-fc8f11c0df7d:indexpattern-datasource-layer-c0671a9e-8335-4bd7-8a0c-01c93204e1c3","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"5b42566d-cfcd-4d05-883b-9c1d5f5e0744:indexpattern-datasource-layer-c0671a9e-8335-4bd7-8a0c-01c93204e1c3","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"e35904ac-37fc-47a0-b7ed-2a18b3ee49a7:indexpattern-datasource-layer-c0671a9e-8335-4bd7-8a0c-01c93204e1c3","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"controlGroup_4e752be6-45d8-4c21-ad1a-b3b624954e94:optionsListDataView","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"controlGroup_3bb18989-7140-474d-bd8b-699027435af4:optionsListDataView","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"controlGroup_13f7c240-f28f-4d21-be79-f98673895ff5:optionsListDataView","type":"index-pattern"},{"id":"784d0077-811c-4d9c-8866-7c6e8a031ab1","name":"controlGroup_610654e8-a14a-41ea-82a2-56532dd21d3c:optionsListDataView","type":"index-pattern"}],"type":"dashboard","typeMigrationVersion":"10.2.0","updated_at":"2025-01-13T09:54:48.519Z","updated_by":"u_H8wCOln3L1V7i_dxli1nxpWKh5fdCOVL1o1TOwqJW7I_0","version":"WzI1MTg2LDYwXQ=="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":2,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/supporting-blog-content/spotify-to-elasticsearch/python/main.py b/supporting-blog-content/spotify-to-elasticsearch/python/main.py new file mode 100644 index 00000000..8148f055 --- /dev/null +++ b/supporting-blog-content/spotify-to-elasticsearch/python/main.py @@ -0,0 +1,187 @@ +import logging +from pathlib import Path +import typer +from datetime import datetime +import json +from rich.logging import RichHandler +from rich.console import Console +from rich.progress import ( + Progress, + SpinnerColumn, + BarColumn, + TaskProgressColumn, + TimeElapsedColumn, +) +from services import SpotifyService, ElasticsearchService +from models import SpotifyTrack + +logger = None + + +def try_parsing_date(text): + """Attempt to parse a date""" + for fmt in ("%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%dT%H:%M:%S.%fZ"): + try: + return datetime.strptime(text, fmt) + except ValueError: + logger.error(f"Error parsing date: {text}") + pass + + +def process_history_file( + file_path: str, + spotify_svc: SpotifyService, + es_svc: ElasticsearchService, + user_name: str, +): + """Main processing function""" + # Set up rich logging + logging.basicConfig( + level=logging.INFO, + format="%(message)s", + handlers=[RichHandler(rich_tracebacks=True)], + ) + logger = logging.getLogger(__name__) + console = Console() + + with open(file_path) as f: + history = json.load(f) + + console.print(f"[green]Processing {file_path}") + + documents = [] + with Progress( + SpinnerColumn(), + "[progress.description]{task.description}", + BarColumn(), + TaskProgressColumn(), + TimeElapsedColumn(), + ) as progress: + task = progress.add_task("[cyan]Processing tracks...", total=len(history)) + + total_entries = len(history) + batch_size = 50 + for i in range(0, total_entries, batch_size): + entries_batch = history[i : i + batch_size] + metadata_batch = spotify_svc.get_tracks_metadata(entries_batch) + for entry in entries_batch: + try: + # let's make sure to only look at songs + # we do not support videos, podcats or + # anything else yet. + if entry["spotify_track_uri"] is not None and entry[ + "spotify_track_uri" + ].startswith("spotify:track:"): + track_id = entry["spotify_track_uri"].replace( + "spotify:track:", "" + ) + metadata = metadata_batch.get(track_id, None) + played_at = try_parsing_date(entry["ts"]) + if metadata is not None: + documents.append( + SpotifyTrack( + id=str( + int( + ( + played_at - datetime(1970, 1, 1) + ).total_seconds() + ) + ) + + "_" + + entry["master_metadata_album_artist_name"], + artist=[ + artist["name"] for artist in metadata["artists"] + ], + album=metadata["album"]["name"], + country=entry["conn_country"], + duration=metadata["duration_ms"], + explicit=metadata["explicit"], + listened_to_pct=( + entry["ms_played"] / metadata["duration_ms"] + if metadata["duration_ms"] > 0 + else None + ), + listened_to_ms=entry["ms_played"], + ip=entry["ip_addr"], + reason_start=entry["reason_start"], + reason_end=entry["reason_end"], + shuffle=entry["shuffle"], + skipped=entry["skipped"], + offline=entry["offline"], + title=metadata["name"], + platform=entry["platform"], + played_at=played_at, + spotify_metadata=metadata, + hourOfDay=played_at.hour, + dayOfWeek=played_at.strftime("%A"), + url=metadata["external_urls"]["spotify"], + user=user_name, + ) + ) + else: + console.print(f"[red]Metadata not found for track: {entry}") + if len(documents) >= 500: + console.print( + f"[green]Indexing batch of tracks... {len(documents)}" + ) + es_svc.bulk_index(documents) + documents = [] + progress.advance(task) + + except Exception as e: + logger.error(f"Error processing track: {e}") + spotify_svc.metadata_cache.save_cache() + raise + + if documents: + console.print(f"[green]Indexing final batch of tracks... {len(documents)}") + es_svc.bulk_index(documents) + console.print(f"[green]Done! {file_path} processed!") + + spotify_svc.metadata_cache.save_cache() + + +app = typer.Typer() + + +@app.command() +def process_history( + es_url: str = typer.Option(..., help="Elasticsearch URL"), + es_api_key: str = typer.Option(..., help="Elasticsearch API Key"), + spotify_client_id: str = typer.Option(None, help="Spotify Client ID"), + spotify_client_secret: str = typer.Option(None, help="Spotify Client Secret"), + user_name: str = typer.Option(None, help="User name"), +): + """Setup the services""" + if spotify_client_id and spotify_client_secret: + spotify_svc = SpotifyService( + client_id=spotify_client_id, + client_secret=spotify_client_secret, + redirect_uri="http://localhost:9100", + ) + es_svc = ElasticsearchService(es_url=es_url, api_key=es_api_key) + # Ensure index exists + es_svc.check_index() + es_svc.check_pipeline() + + files = list(Path("to_read").glob("*Audio*.json")) + if not files: + raise ValueError( + "No JSON files found in 'to_read' directory, expected them to be named *Audio*.json, like Streaming_History_Audio_2023_8.json" + ) + else: + for file_path in files: + process_history_file(file_path, spotify_svc, es_svc, user_name) + move_file(file_path) + + +def move_file(file_path: Path): + """Move the file to the 'processed' directory""" + processed_dir = Path("processed") + processed_dir.mkdir(exist_ok=True) + new_path = Path("processed") / file_path.name + file_path.rename(new_path) + + +if __name__ == "__main__": + app() diff --git a/supporting-blog-content/spotify-to-elasticsearch/python/models.py b/supporting-blog-content/spotify-to-elasticsearch/python/models.py new file mode 100644 index 00000000..3fa76ac6 --- /dev/null +++ b/supporting-blog-content/spotify-to-elasticsearch/python/models.py @@ -0,0 +1,54 @@ +from dataclasses import dataclass +from datetime import datetime +from typing import Optional + + +@dataclass +class SpotifyTrack: + """A class representing a Spotify track with its metadata and listening context. + + Attributes: + id (str): The unique identifier of the track. + album (str): The name of the album containing the track. + artist (list[str]): List of artist names associated with the track. + country (str): The country where the track was played. + dayOfWeek (str): The day of the week when the track was played. + duration (int): Duration of the track in milliseconds. + explicit (bool): Whether the track has explicit content. + hourOfDay (int): The hour of the day when the track was played (0-23). + listened_to (float, optional): The duration listened to in milliseconds. Defaults to None. + ip (str): The IP address of the device that played the track. + offline (bool): Whether the track was played in offline mode. + reason_start (str): The reason why the track started playing. + reason_end (str): The reason why the track stopped playing. + platform (str): The platform used to play the track. + played_at (datetime): The timestamp when the track was played. + skipped (bool): Whether the track was skipped. + title (str): The title of the track. + url (str): The Spotify URL of the track. + user (str): The user who played the track. + user_agent (str): The user agent string of the device used to play the track. + """ + + id: str + album: str + artist: list[str] + country: str + dayOfWeek: str + duration: int + explicit: bool + hourOfDay: int + listened_to_ms: int + offline: bool + reason_start: str + reason_end: str + platform: str + played_at: datetime + shuffle: bool + skipped: bool + title: str + url: str + user: Optional[str] = None + listened_to_pct: Optional[float] = None + ip: Optional[str] = None + spotify_metadata: Optional[dict] = None diff --git a/supporting-blog-content/spotify-to-elasticsearch/python/services.py b/supporting-blog-content/spotify-to-elasticsearch/python/services.py new file mode 100644 index 00000000..690f1ad8 --- /dev/null +++ b/supporting-blog-content/spotify-to-elasticsearch/python/services.py @@ -0,0 +1,165 @@ +from pathlib import Path +import json +from typing import Dict, List +from elasticsearch import Elasticsearch, helpers, exceptions +from rich.console import Console +import spotipy +from spotipy.oauth2 import SpotifyOAuth +from models import SpotifyTrack + +console = Console() + + +class MetadataCache: + def __init__(self, cache_file: Path = Path("metadata_cache.json")): + self.cache_file = cache_file + self.cache = self._load_cache() + + def _load_cache(self) -> Dict: + if self.cache_file.exists(): + return json.loads(self.cache_file.read_text()) + return {} + + def save_cache(self): + console.print(f"[green] Saving cache to disk {len(self.cache)}") + self.cache_file.write_text(json.dumps(self.cache)) + + +class SpotifyService: + def __init__(self, client_id: str, client_secret: str, redirect_uri: str): + self.client = spotipy.Spotify( + auth_manager=SpotifyOAuth( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + ), + requests_timeout=30, + ) + self.metadata_cache = MetadataCache() + + def get_tracks_metadata(self, track_ids: str) -> Dict: + metadatas = {} + to_fetch = [] + for track_id in track_ids: + if track_id["spotify_track_uri"] is not None and track_id[ + "spotify_track_uri" + ].startswith("spotify:track:"): + track_id = track_id["spotify_track_uri"].replace("spotify:track:", "") + if self.metadata_cache.cache.get(track_id, None) is not None: + metadatas[track_id] = self.metadata_cache.cache[track_id] + else: + to_fetch.append(track_id) + if len(to_fetch) > 0: + spotify_answer = self.client.tracks(to_fetch) + if spotify_answer["tracks"] is not None: + # Spotify can be a bit annoying and send back an Array that has `None` in it. + spotify_answer["tracks"] = [ + t for t in spotify_answer["tracks"] if t is not None + ] + if len(to_fetch) != len(spotify_answer["tracks"]): + for missing_id in set(to_fetch) - { + t["id"] for t in spotify_answer["tracks"] + }: + console.print( + f"[red] Could not fetch metadata for track id: {missing_id}" + ) + if len(spotify_answer["tracks"]) > 0: + for track in spotify_answer["tracks"]: + metadatas[track["id"]] = track + self.metadata_cache.cache[track["id"]] = track + else: + console.print( + f"[red] Could not fetch metadata from Spotify. {to_fetch}" + ) + return metadatas + + +class ElasticsearchService: + def __init__(self, es_url: str, api_key: str, index: str = "spotify-history"): + self.client = Elasticsearch(hosts=es_url, api_key=api_key, request_timeout=30) + self.index = index + + def check_pipeline(self): + pipeline = {"processors": [{"geoip": {"field": "ip", "ignore_failure": True}}]} + try: + self.client.ingest.put_pipeline(id="spotify", body=pipeline) + except exceptions.RequestError as e: + console.print( + f"[red] Could not ingest the pipeline. Check permissions. {e}" + ) + + def check_index(self): + if self.client.indices.exists(index=self.index).body is False: + self.client.indices.create( + index=self.index, + settings={"final_pipeline": "spotify"}, + mappings={ + "dynamic": "true", + "dynamic_date_formats": [ + "strict_date_optional_time", + "yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z", + ], + "dynamic_templates": [ + { + "stringsaskeywords": { + "match": "*", + "match_mapping_type": "string", + "mapping": {"type": "keyword"}, + } + } + ], + "date_detection": True, + "numeric_detection": False, + "properties": { + "@timestamp": { + "type": "date", + "format": "strict_date_optional_time", + }, + "album": {"type": "keyword"}, + "artist": {"type": "keyword"}, + "dayOfWeek": {"type": "keyword"}, + "duration": {"type": "long"}, + "explicit": {"type": "boolean"}, + "geoip": { + "properties": { + "city_name": {"type": "keyword"}, + "continent_name": {"type": "keyword"}, + "country_iso_code": {"type": "keyword"}, + "country_name": {"type": "keyword"}, + "location": {"type": "geo_point"}, + "region_iso_code": {"type": "keyword"}, + "region_name": {"type": "keyword"}, + } + }, + "hourOfDay": {"type": "long"}, + "ip": {"type": "ip"}, + "not_found": {"type": "boolean"}, + "offline": {"type": "boolean"}, + "platform": {"type": "keyword"}, + "played_at": { + "type": "date", + "format": "strict_date_optional_time", + }, + "reason_end": {"type": "keyword"}, + "reason_start": {"type": "keyword"}, + "skipped": {"type": "boolean"}, + "title": {"type": "keyword"}, + "url": {"type": "keyword"}, + "user": {"type": "keyword"}, + }, + }, + ) + + def bulk_index(self, documents: List[SpotifyTrack]): + actions = [ + { + "_index": self.index, + "_id": doc.id, + "_source": {**vars(doc), "@timestamp": doc.played_at}, + } + for doc in documents + ] + return helpers.bulk( + self.client, + actions, + ) diff --git a/supporting-blog-content/spotify-to-elasticsearch/requirements.txt b/supporting-blog-content/spotify-to-elasticsearch/requirements.txt new file mode 100644 index 00000000..5e9fee7b --- /dev/null +++ b/supporting-blog-content/spotify-to-elasticsearch/requirements.txt @@ -0,0 +1,4 @@ +spotipy +elasticsearch +rich +typer \ No newline at end of file