tracks(3)

๐Ÿ“ฆ version 1.1.23, in arch rolling

๐ŸŒธ NAME ๐ŸŒธ

tracks โ€” The track management API ๐Ÿ’– (this is the tracks(3) page, bestie, welcome to the track zone ๐ŸŽ€)


โœจ SYNOPSIS โœจ

Functions

  • LIBMTP_track_t * LIBMTP_new_track_t (void)
  • void LIBMTP_destroy_track_t (LIBMTP_track_t *)
  • LIBMTP_track_t * LIBMTP_Get_Tracklisting (LIBMTP_mtpdevice_t *)
  • LIBMTP_track_t * LIBMTP_Get_Tracklisting_With_Callback (LIBMTP_mtpdevice_t *, LIBMTP_progressfunc_t const, void const *const)
  • LIBMTP_track_t * LIBMTP_Get_Tracklisting_With_Callback_For_Storage (LIBMTP_mtpdevice_t *, uint32_t const, LIBMTP_progressfunc_t const, void const *const)
  • LIBMTP_track_t * LIBMTP_Get_Trackmetadata (LIBMTP_mtpdevice_t *, uint32_t const)
  • int LIBMTP_Get_Track_To_File (LIBMTP_mtpdevice_t *, uint32_t, char const *const, LIBMTP_progressfunc_t const, void const *const)
  • int LIBMTP_Get_Track_To_File_Descriptor (LIBMTP_mtpdevice_t *, uint32_t const, int const, LIBMTP_progressfunc_t const, void const *const)
  • int LIBMTP_Get_Track_To_Handler (LIBMTP_mtpdevice_t *, uint32_t const, MTPDataPutFunc, void *, LIBMTP_progressfunc_t const, void const *const)
  • int LIBMTP_Send_Track_From_File (LIBMTP_mtpdevice_t *, char const *const, LIBMTP_track_t *const, LIBMTP_progressfunc_t const, void const *const)
  • int LIBMTP_Send_Track_From_File_Descriptor (LIBMTP_mtpdevice_t *, int const, LIBMTP_track_t *const, LIBMTP_progressfunc_t const, void const *const)
  • int LIBMTP_Send_Track_From_Handler (LIBMTP_mtpdevice_t *, MTPDataGetFunc, void *, LIBMTP_track_t *const, LIBMTP_progressfunc_t const, void const *const)
  • int LIBMTP_Update_Track_Metadata (LIBMTP_mtpdevice_t *, LIBMTP_track_t const *const)
  • int LIBMTP_Track_Exists (LIBMTP_mtpdevice_t *, uint32_t const)
  • int LIBMTP_Set_Track_Name (LIBMTP_mtpdevice_t *, LIBMTP_track_t *, const char *)

๐Ÿ’… Detailed Description ๐Ÿ’…

Okay so this is the part where all the juicy details live โ€” every function below gets its own little spotlight moment, with params, returns, and the whole "see also" friend group tagged along. Scroll on, bestie ๐Ÿ‘‘โœจ


๐ŸŽ€ Function Documentation ๐ŸŽ€

๐Ÿ’– void LIBMTP_destroy_track_t (LIBMTP_track_t * track)

This one destroys a track metadata structure โ€” and like, destroys destroys, it deallocates all the memory that structure was using, strings included. ๐Ÿซถ

โš ๏ธ Never use a track metadata structure again after you've called this function on it. Like, ever. That memory is gone-gone, no cap ๐Ÿ’€

Parameters

  • track โ€” the track metadata to destroy.

See also

  • LIBMTP_new_track_t()

References LIBMTP_track_struct::album, LIBMTP_track_struct::artist, LIBMTP_track_struct::composer, LIBMTP_track_struct::date, LIBMTP_track_struct::filename, LIBMTP_track_struct::genre, and LIBMTP_track_struct::title.

Referenced by LIBMTP_Get_Tracklisting_With_Callback_For_Storage(), and LIBMTP_Get_Trackmetadata().


๐ŸŒˆ int LIBMTP_Get_Track_To_File (LIBMTP_mtpdevice_t * device, uint32_t const id, char const *const path, LIBMTP_progressfunc_t const callback, void const *const data)

This pulls a track off the device and drops it into a file, identified by a filename. Fun fact: this is actually just a wrapper for the LIBMTP_Get_Track_To_File() function. Yes bestie, it says what it says ๐Ÿ˜ญ๐Ÿ’…

Parameters

  • device โ€” a pointer to the device to get the track from.
  • id โ€” the track ID of the track to retrieve.
  • path โ€” a filename to use for the retrieved track.
  • callback โ€” a progress indicator function or NULL to ignore.
  • data โ€” a user-defined pointer that is passed along to the progress function in order to pass along some user defined data to the progress updates. If not used, set this to NULL.

Returns

0 if the transfer was successful, any other value means failure. ๐Ÿ“

See also

  • LIBMTP_Get_Track_To_File_Descriptor()

References LIBMTP_Get_File_To_File().


๐Ÿฆ‹ int LIBMTP_Get_Track_To_File_Descriptor (LIBMTP_mtpdevice_t * device, uint32_t const id, int const fd, LIBMTP_progressfunc_t const callback, void const *const data)

Same energy as the last one, but this time the track goes into a file identified by a file descriptor instead of a filename. And yep โ€” this is actually just a wrapper for the LIBMTP_Get_File_To_File_Descriptor() function โœจ

Parameters

  • device โ€” a pointer to the device to get the track from.
  • id โ€” the track ID of the track to retrieve.
  • fd โ€” a file descriptor to write the track to.
  • callback โ€” a progress indicator function or NULL to ignore.
  • data โ€” a user-defined pointer that is passed along to the progress function in order to pass along some user defined data to the progress updates. If not used, set this to NULL.

Returns

0 if the transfer was successful, any other value means failure. ๐Ÿ“

See also

  • LIBMTP_Get_Track_To_File()

References LIBMTP_Get_File_To_File_Descriptor().


๐Ÿงš int LIBMTP_Get_Track_To_Handler (LIBMTP_mtpdevice_t * device, uint32_t const id, MTPDataPutFunc put_func, void * priv, LIBMTP_progressfunc_t const callback, void const *const data)

And this one gets a track off the device straight into a handler function. It's actually just a wrapper for the LIBMTP_Get_File_To_Handler() function. We love a consistent family ๐Ÿ™ˆ๐Ÿ’œ

Parameters

  • device โ€” a pointer to the device to get the track from.
  • id โ€” the track ID of the track to retrieve.
  • put_func โ€” the function to call when we have data.
  • priv โ€” the user-defined pointer that is passed to put_func.
  • callback โ€” a progress indicator function or NULL to ignore.
  • data โ€” a user-defined pointer that is passed along to the progress function in order to pass along some user defined data to the progress updates. If not used, set this to NULL.

Returns

0 if the transfer was successful, any other value means failure. ๐Ÿ“

References LIBMTP_Get_File_To_Handler().


๐Ÿ’€ LIBMTP_track_t * LIBMTP_Get_Tracklisting (LIBMTP_mtpdevice_t * device)

๐Ÿšจ THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER NOT TO USE IT. ๐Ÿšจ

Like, seriously bestie, it's giving "please move on" energy ๐Ÿ˜ญ โ€” go use the callback version instead.

See also

  • LIBMTP_Get_Tracklisting_With_Callback()

References LIBMTP_Get_Tracklisting_With_Callback().


๐Ÿ‘‘ LIBMTP_track_t * LIBMTP_Get_Tracklisting_With_Callback (LIBMTP_mtpdevice_t * device, LIBMTP_progressfunc_t const callback, void const *const data)

This returns a long list of all the tracks available on the current MTP device. And "tracks" here is inclusive โ€” it covers multimedia objects, both music tracks and video tracks. Obsessed with the range ๐Ÿ”ฅ

Typical usage goes a lil something like this:

LIBMTP_track_t *tracklist;

tracklist = LIBMTP_Get_Tracklisting_With_Callback(device, callback, data);
while (tracklist != NULL) {
  LIBMTP_track_t *tmp;

  // Do something on each element in the list here...
  tmp = tracklist;
  tracklist = tracklist->next;
  LIBMTP_destroy_track_t(tmp);
}

So if you wanna group your track listing by storage (per storage unit) or arrange tracks into folders, you must dereference the storage_id and/or parent_id field of the returned LIBMTP_track_t struct. And to arrange by folders or files, you typically have to create the proper trees by calling LIBMTP_Get_Storage() and/or LIBMTP_Get_Folder_List() first. iykyk ๐ŸŒธ

Parameters

  • device โ€” a pointer to the device to get the track listing for.
  • callback โ€” a function to be called during the tracklisting retrieveal for displaying progress bars etc, or NULL if you don't want any callbacks.
  • data โ€” a user-defined pointer that is passed along to the progress function in order to pass along some user defined data to the progress updates. If not used, set this to NULL.

Returns

a list of tracks that can be followed using the next field of the LIBMTP_track_t data structure. Each of the metadata tags must be freed after use, and may contain only partial metadata information, i.e. one or several fields may be NULL or 0. ๐Ÿ™ˆ

See also

  • LIBMTP_Get_Trackmetadata()

References LIBMTP_Get_Tracklisting_With_Callback_For_Storage().

Referenced by LIBMTP_Get_Tracklisting().


๐ŸŽ€ LIBMTP_track_t * LIBMTP_Get_Tracklisting_With_Callback_For_Storage (LIBMTP_mtpdevice_t * device, uint32_t const storage_id, LIBMTP_progressfunc_t const callback, void const *const data)

Same big energy as above โ€” this returns a long list of all tracks available on the current MTP device, and tracks include multimedia objects, both music tracks and video tracks. But this time you get to say which storage you're looking at ๐Ÿ’…

Typical usage:

LIBMTP_track_t *tracklist;

tracklist = LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, storage_id, callback, data);
while (tracklist != NULL) {
  LIBMTP_track_t *tmp;

  // Do something on each element in the list here...
  tmp = tracklist;
  tracklist = tracklist->next;
  LIBMTP_destroy_track_t(tmp);
}

Same deal as before, boo: if you want to group your track listing by storage (per storage unit) or arrange tracks into folders, you must dereference the storage_id and/or parent_id field of the returned LIBMTP_track_t struct. To arrange by folders or files you typically have to create the proper trees by calls to LIBMTP_Get_Storage() and/or LIBMTP_Get_Folder_List() first. ๐Ÿฆ‹

Parameters

  • device โ€” a pointer to the device to get the track listing for.
  • storage_id โ€” ID of device storage (if null, no filter)
  • callback โ€” a function to be called during the tracklisting retrieveal for displaying progress bars etc, or NULL if you don't want any callbacks.
  • data โ€” a user-defined pointer that is passed along to the progress function in order to pass along some user defined data to the progress updates. If not used, set this to NULL.

Returns

a list of tracks that can be followed using the next field of the LIBMTP_track_t data structure. Each of the metadata tags must be freed after use, and may contain only partial metadata information, i.e. one or several fields may be NULL or 0. ๐Ÿ™ˆ

See also

  • LIBMTP_Get_Trackmetadata()

References LIBMTP_track_struct::filename, LIBMTP_track_struct::filesize, LIBMTP_track_struct::filetype, LIBMTP_track_struct::item_id, LIBMTP_destroy_track_t(), LIBMTP_FILETYPE_IS_TRACK, LIBMTP_new_track_t(), LIBMTP_track_struct::modificationdate, LIBMTP_track_struct::next, LIBMTP_mtpdevice_struct::params, LIBMTP_track_struct::parent_id, LIBMTP_track_struct::storage_id, and LIBMTP_mtpdevice_struct::usbinfo.

Referenced by LIBMTP_Get_Tracklisting_With_Callback().


โญ LIBMTP_track_t * LIBMTP_Get_Trackmetadata (LIBMTP_mtpdevice_t * device, uint32_t const trackid)

This function retrieves the metadata for a single track off the device. One. Uno. Singular. ๐Ÿ’…

๐Ÿ˜ญ Do not call this function repeatedly! The track handles are linearly searched O(n) and the call may involve (slow) USB traffic, so use LIBMTP_Get_Tracklisting() and cache the tracks, preferably as an efficient data structure such as a hash list. Please bestie, your USB bus is begging you ๐Ÿ™

Parameters

  • device โ€” a pointer to the device to get the track metadata from.
  • trackid โ€” the object ID of the track that you want the metadata for.

Returns

a track metadata entry on success or NULL on failure. โœจ

See also

  • LIBMTP_Get_Tracklisting()

โ€ฆand fr, that one is lowkey connected to a whole friend group of internals โ€” it references all of these besties:

  • LIBMTP_track_struct::filename
  • LIBMTP_track_struct::filesize
  • LIBMTP_track_struct::filetype
  • LIBMTP_track_struct::item_id
  • LIBMTP_destroy_track_t()
  • LIBMTP_FILETYPE_IS_TRACK
  • LIBMTP_new_track_t()
  • LIBMTP_track_struct::modificationdate
  • LIBMTP_mtpdevice_struct::params
  • LIBMTP_track_struct::parent_id
  • LIBMTP_track_struct::storage_id
  • LIBMTP_mtpdevice_struct::usbinfo

๐ŸŒฑ LIBMTP_track_t * LIBMTP_new_track_t (void )

Bestie, this is your fresh start function. It creates a brand new track metadata structure and allocates memory for it, so likeโ€ฆ newborn track energy ๐Ÿ‘ถโœจ

But hear me out โ€” the important part: if you add strings to this structure, they will be freed by the corresponding LIBMTP_destroy_track_t operation later. So be careful about using strdup() when you assign strings, okay? Like this:

LIBMTP_track_t *track = LIBMTP_new_track_t();
track->title = strdup(titlestr);
....
LIBMTP_destroy_track_t(track);

See how the strdup() is doing the heavy lifting? That's the move. Your strings need their own copy or the destroy step is gonna have opinions ๐Ÿ’€

Returns

a pointer to the newly allocated metadata structure. Slay โœจ

See also

LIBMTP_destroy_track_t() โ€” the other half of this situationship ๐Ÿซถ

Referenced by LIBMTP_Get_Tracklisting_With_Callback_For_Storage(), and LIBMTP_Get_Trackmetadata().


๐Ÿ“ค int LIBMTP_Send_Track_From_File (LIBMTP_mtpdevice_t * device, char const *const path, LIBMTP_track_t *const metadata, LIBMTP_progressfunc_t const callback, void const *const data)

Okay so this one sends a track from a local file to an MTP device. A filename and a set of metadata must be given as input โ€” that's the whole vibe check โœ…

Parameters

  • device โ€” a pointer to the device to send the track to.
  • path โ€” the filename of a local file which will be sent.
  • metadata โ€” a track metadata set to be written along with the file. Heads up bestie: after this call, the field metadata->item_id will contain the new track ID. Other fields such as the metadata->filename, metadata->parent_id or metadata->storage_id may also change during this operation due to device restrictions, so do not rely on the contents of this struct to be preserved in any way ๐Ÿ˜ญ It goes in, it comes out different, that's just the plot.
    • metadata->parent_id should be set to the parent (e.g. folder) to store this track in. Since some devices are a bit picky about where files are placed, a default folder will be chosen if libmtp has detected one for the current filetype and this parameter is set to 0. If this is 0 and no default folder can be found, the file will be stored in the root folder.
    • metadata->storage_id should be set to the desired storage (e.g. memory card or whatever your device presents) to store this track in. Setting this to 0 will store the track on the primary storage.
  • callback โ€” a progress indicator function or NULL to ignore.
  • data โ€” a user-defined pointer that is passed along to the progress function in order to pass along some user defined data to the progress updates. If not used, set this to NULL.

Returns

0 if the transfer was successful, any other value means failure. No in-between, it's giving all-or-nothing ๐Ÿ’…

See also

LIBMTP_Send_Track_From_File_Descriptor()

LIBMTP_Send_File_From_File()

LIBMTP_Delete_Object()

References LIBMTP_Send_Track_From_File_Descriptor().


๐Ÿ“ฅ int LIBMTP_Send_Track_From_File_Descriptor (LIBMTP_mtpdevice_t * device, int const fd, LIBMTP_track_t *const metadata, LIBMTP_progressfunc_t const callback, void const *const data)

Same energy as the one above, but the source is a file descriptor instead of a path. This function sends a track from a file descriptor to an MTP device. A filename and a set of metadata must be given as input.

Parameters

  • device โ€” a pointer to the device to send the track to.
  • fd โ€” the filedescriptor for a local file which will be sent.
  • metadata โ€” a track metadata set to be written along with the file. After this call the field metadata->item_id will contain the new track ID. Other fields such as the metadata->filename, metadata->parent_id or metadata->storage_id may also change during this operation due to device restrictions, so do not rely on the contents of this struct to be preserved in any way ๐Ÿซ 
    • metadata->parent_id should be set to the parent (e.g. folder) to store this track in. Since some devices are a bit picky about where files are placed, a default folder will be chosen if libmtp has detected one for the current filetype and this parameter is set to 0. If this is 0 and no default folder can be found, the file will be stored in the root folder.
    • metadata->storage_id should be set to the desired storage (e.g. memory card or whatever your device presents) to store this track in. Setting this to 0 will store the track on the primary storage.
  • callback โ€” a progress indicator function or NULL to ignore.
  • data โ€” a user-defined pointer that is passed along to the progress function in order to pass along some user defined data to the progress updates. If not used, set this to NULL.

Returns

0 if the transfer was successful, any other value means failure.

See also

LIBMTP_Send_Track_From_File()

LIBMTP_Delete_Object()

References LIBMTP_file_struct::filename, LIBMTP_track_struct::filename, LIBMTP_file_struct::filesize, LIBMTP_track_struct::filesize, LIBMTP_file_struct::filetype, LIBMTP_track_struct::filetype, LIBMTP_file_struct::item_id, LIBMTP_track_struct::item_id, LIBMTP_FILETYPE_IS_TRACK, LIBMTP_Send_File_From_File_Descriptor(), LIBMTP_Update_Track_Metadata(), LIBMTP_file_struct::next, LIBMTP_mtpdevice_struct::params, LIBMTP_file_struct::parent_id, LIBMTP_track_struct::parent_id, LIBMTP_file_struct::storage_id, LIBMTP_track_struct::storage_id, and LIBMTP_mtpdevice_struct::usbinfo.

Referenced by LIBMTP_Send_Track_From_File().


๐Ÿงš int LIBMTP_Send_Track_From_Handler (LIBMTP_mtpdevice_t * device, MTPDataGetFunc get_func, void * priv, LIBMTP_track_t *const metadata, LIBMTP_progressfunc_t const callback, void const *const data)

And here's the third sibling in the send-track trio ๐ŸŽ€ This function sends a track from a handler function to an MTP device. A filename and a set of metadata must be given as input.

Parameters

  • device โ€” a pointer to the device to send the track to.
  • get_func โ€” the function to call when we have data.
  • priv โ€” the user-defined pointer that is passed to get_func.
  • metadata โ€” a track metadata set to be written along with the file. After this call the field metadata->item_id will contain the new track ID. Other fields such as the metadata->filename, metadata->parent_id or metadata->storage_id may also change during this operation due to device restrictions, so do not rely on the contents of this struct to be preserved in any way ๐Ÿ˜ฎโ€๐Ÿ’จ
    • metadata->parent_id should be set to the parent (e.g. folder) to store this track in. Since some devices are a bit picky about where files are placed, a default folder will be chosen if libmtp has detected one for the current filetype and this parameter is set to 0. If this is 0 and no default folder can be found, the file will be stored in the root folder.
    • metadata->storage_id should be set to the desired storage (e.g. memory card or whatever your device presents) to store this track in. Setting this to 0 will store the track on the primary storage.
  • callback โ€” a progress indicator function or NULL to ignore.
  • data โ€” a user-defined pointer that is passed along to the progress function in order to pass along some user defined data to the progress updates. If not used, set this to NULL.

Returns

0 if the transfer was successful, any other value means failure.

See also

LIBMTP_Send_Track_From_File()

LIBMTP_Delete_Object()

References LIBMTP_file_struct::filename, LIBMTP_track_struct::filename, LIBMTP_file_struct::filesize, LIBMTP_track_struct::filesize, LIBMTP_file_struct::filetype, LIBMTP_track_struct::filetype, LIBMTP_file_struct::item_id, LIBMTP_track_struct::item_id, LIBMTP_FILETYPE_IS_TRACK, LIBMTP_Send_File_From_Handler(), LIBMTP_Update_Track_Metadata(), LIBMTP_file_struct::next, LIBMTP_mtpdevice_struct::params, LIBMTP_file_struct::parent_id, LIBMTP_track_struct::parent_id, LIBMTP_file_struct::storage_id, LIBMTP_track_struct::storage_id, and LIBMTP_mtpdevice_struct::usbinfo.


โœ๏ธ int LIBMTP_Set_Track_Name (LIBMTP_mtpdevice_t * device, LIBMTP_track_t * track, const char * newname)

Rebranding era ๐ŸŒˆ This function renames a single track. And like, "renames" here means something very specific: it simply means that the PTP_OPC_ObjectFileName property is updated, if this is supported by the device. So no promises if your device is being difficult.

Parameters

  • device โ€” a pointer to the device that contains the file.
  • track โ€” the track metadata of the track to rename. On success, the filename member is updated. Be aware, that this name can be different than newname depending of device restrictions. Yeah. You asked for one thing, the device gave you another ๐Ÿ™ˆ
  • newname โ€” the new filename for this object.

Returns

0 on success, any other value means failure.

References LIBMTP_track_struct::filename, LIBMTP_track_struct::filetype, and LIBMTP_track_struct::item_id.


๐Ÿ” int LIBMTP_Track_Exists (LIBMTP_mtpdevice_t * device, uint32_t const id)

Helper function moment ๐Ÿซถ This indicates if a track exists on the device. That's it, that's the whole job โ€” a little vibe check for your track.

Parameters

  • device โ€” a pointer to the device to get the track from.
  • id โ€” the track ID of the track to retrieve.

Returns

TRUE (!=0) if the track exists, FALSE (0) if not.

References LIBMTP_mtpdevice_struct::params.


๐Ÿ”„ int LIBMTP_Update_Track_Metadata (LIBMTP_mtpdevice_t * device, LIBMTP_track_t const *const metadata)

Glow-up time for your tags โœจ This function updates the MTP track object metadata on a single file identified by an object ID.

Parameters

  • device โ€” a pointer to the device to update the track metadata on.
  • metadata โ€” a track metadata set to be written to the file. Notice that the track_id field of the metadata structure must be correct so that the function can update the right file. And here's the lil catch: if some properties of this metadata are set to NULL (strings) or 0 (numerical values) they will be discarded and the track will not be tagged with these blank values. So blank in โ‰  blank out, it's more like blank in = nothing happens ๐Ÿ’€

Returns

0 on success, any other value means failure. But bestie, read this carefully: if some or all of the properties fail to update we will still return success. Yeah, I know. On some devices (notably iRiver T30) properties that exist cannot be updated. So success is doing a lot of heavy lifting here ๐Ÿ˜ญ

References LIBMTP_track_struct::album, LIBMTP_track_struct::artist, LIBMTP_track_struct::bitrate, LIBMTP_track_struct::bitratetype, LIBMTP_track_struct::composer, LIBMTP_track_struct::date, LIBMTP_track_struct::duration, LIBMTP_track_struct::filetype, LIBMTP_track_struct::genre, LIBMTP_track_struct::item_id, LIBMTP_track_struct::nochannels, LIBMTP_mtpdevice_struct::params, LIBMTP_track_struct::rating, LIBMTP_track_struct::samplerate, LIBMTP_track_struct::title, LIBMTP_track_struct::tracknumber, LIBMTP_mtpdevice_struct::usbinfo, LIBMTP_track_struct::usecount, and LIBMTP_track_struct::wavecodec.

Referenced by LIBMTP_Send_Track_From_File_Descriptor(), and LIBMTP_Send_Track_From_Handler().

๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

Ok so nobody hand-wrote this one bestie โ€” she's auto-generated:

Generated automatically by Doxygen for libmtp from the source code.

That's it, that's the whole author section ๐Ÿ’… no mysterious human genius to thank, no mailto: to slide into, just Doxygen doing her little robot thing from the libmtp source and signing her name at the bottom. Iconic behaviour honestly, she said "I don't need credit, the build system has me covered" โœจ


๐ŸŽ€ and that's a wrap, bestie ๐ŸŽ€

You made it to the very end of tracks(3) โ€” look at you, all that function documentation absorbed, main character energy fr fr ๐Ÿ’–

Just so we're keeping it ๐Ÿ’ฏ with all the boring-but-important metadata: this page is from libmtp, Version 1.1.23, and she's the tracks(3) man page โ€” that's the whole footer situation, no extra dates or secrets hiding down here, just the source, the version, and the page name ๐ŸŒธ

Go forth and slay your playlist code, bestie ๐Ÿฆ‹๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from