Playlist
This plugin is a list of external media that are pre-defined and setup ahead of time by the world creator.
The playlist has two parts to it: the inspector and the template
Getting Started
ProTV comes with a pre-made setup for the Playlist plugin. This can be found in the Packages/ArchiTech.ProTV/Samples/Prefabs/Plugins
folder.
Just drag the Playlist prefab into the scene and assign your desired TV to it. You can adjust various aspects of the playlists as desired.
If you want to have the playlist send the entries to a Queue instead of directly to the TV, just add a Queue to the scene and connect it to the respective slot.
Inspector
TV References
TV
The instance of ProTV that this component will interact with and send media to. You will need to insert the desired TV reference (the game object with theTVManager
script on it), or if you are using a ready-made prefab, it should already be connected.Queue
Optional field where you can specify a Queue plugin object that you wish to make the playlist connect with. If a Queue is provided, then instead of immediately playing the URL a user clicks on, the playlist will forward the desired URL entry into the Queue directly and the Queue then handles the rest.
General Settings
Playlist Storage
Reference to an alternate component for storing the internal playlist data. This is automatically used when a playlist is more than 100 entries. It is a mitigation to lag that happens when a significant amount of serialized data exists on a single object caused by the unity serializer when visible in the inspector.Preload Queue Amount
If a Queue reference is connected, this setting defines how many of the playlist entries should be automatically added to the Queue when the instance master first joins the world. This happens only once per world instance.Shuffle Playlist on Load
Specifies whether to scramble the playlist order when the world loads or not. While the exact shuffle ordering itself isn't synced across users, this is not an issue as the playlist was designed to handle arbitrary ordering from the start.Show Urls in Playlist?
This toggle makes the playlist template skip displaying the URL for each entry. This is useful if you want to hide what domain/source of the media.Autofill Android Urls
This toggle enables the autofill feature for dynamically generating alternate urls for the corresponding main url.
NOTE: Autofill will only happen with this flag enabled and only when clicking Import OR when manually modifying a main URL field.Autofill Format
Text field that specifies the format for the autofill feature. It does a basic string replace where the text$URL
is replaced with the main url value.
Example: If main url ishttps://youtu.be/VIDEO_ID
and format ishttps://mysite.tld/?url=$URL
, the alternate url would be likehttps://mysite.tld/?url=https://youtu.be/VIDEO_ID
.
Autoplay Options
Autoplay Enabled
This flag determines whether the playlist should auto-play be active by default. This is a general setting for whether auto-play logic runs when media ends.Loop Playlist
Determines if the playlist should continue playing media from the start of the entries or not once it reaches the end of the list. Having this disabled is useful for playlists that handle show series or a specific sequential list that you might not want to force the users to continue watching once it finishes.Autoplay on Load
Specifies whether this playlist should attempt to start playing media automatically as soon as the first user joins into a world. This setting only affects the first user to join or if the TV is set to not sync to the owner.Start Autoplay From Random Entry
When enabled, the playlist will initialize at some random entry in the list. This is generally paired with theAutoplay on Load
option.Enable Autoplay on Interact
This flag makes the playlist auto-play become enabled implicitly when a user interacts with the playlist. Combine this withDisable Autoplay on Custom Media
andPrioritize on Interact
to effectively have a 'toggle' between user-entered media and the playlist handling things.Disable Autoplay on Interact
This flag makes the playlist auto-play become disabled implicitly when a user interacts with the playlist. This is useful for having a playlist run automatically on join, but stop auto-playing when a user picks a video manually.Enable Autoplay on Custom Media
This flag enables the autoplay flag when a url is successfully loaded that is NOT in the respective playlist. Much less common use, but can help in certain rare scenarios.Disable Autoplay on Custom Media
This flag disables the autoplay flag when a url is successfully loaded that is NOT in the respective playlist. This pairs well withEnable Autoplay on Interact
.Prioritize on Interact
This flag determines if the playlist should make the attached TV prioritize itself above all other connected playlists. This means that if a TV has multiple playlists associated with it, when a user interacts with a given playlist that has this flag enabled, it will force itself to the front of the line for events from the TV, which makes it able to auto-play before any other playlists might try.Continue From Last Known Entry
The playlist has an internal value that keeps track of what index it triggered last. If this is enabled, it will use that value to determine which media to play next. Otherwise the playlist will start at the very first entry.
Media Entries
First is a simple helper button.
Update Scene
This button is for manually trigger the scene to recalculate stuff for the playlist layout and content. For most actions, this is triggered automatically (like while importing a playlist), but for things like modifying the Template content, clicking this button is required to have the layout update itself.
Next, the playlist entries list has three operating modes. These modes are selected via the dropdown at the top of the Media Entries section.
Manual Entry
When set toManual
, the playlist has various buttons for manipulating the contents of the list. The two global buttons are self-explanatoryAdd Entry
andRemove All
.
For each entry there areMain URL
,Alt URL
,Title
andTags
fields as well as anImage
input.Local Importing
In order to make handling large playlists less painful, ProTV comes with a options to export and import playlists into a tokenized file format.
When set toIn Project
is enabled, the playlist switches to the import mode. All entry manipulation actions are disabled to signify the data is sourced from an asset file, and the global buttons are replaced with aTextAsset
field.
Put the desired playlist file into this slot and click theImport
button to update the contents of the playlist to that of the given file.
If any.playlist
files are detected in the project, an additional dropdown next to the input field is provided for convenience that lists all detected playlists.Remote Importing
When set toRemote URL
, a text input field is provided for inputting a remotely hosted playlist link.
If a link is detected, you can click the Download button to get a cached version of the playlist into your project (it gets cached intoAssets/ProTV/RemotePlaylists
folder). For large playlists, the download button will switch to a progress percentage.
Once downloaded, the button will switch to an Import action to apply the playlist file contents to the component.
Remote URL playlist caches are named with this scheme: {SceneManager.GetActiveScene().name}-{Math.Abs(importUrl.GetHashCode())}{importUrl.Length}.playlist
This allows for consistent file writes for the same URL with very low name collision risk.
Additionally, if you have cached your playlist recently and don't wish to download it, you can switch to In Project
mode and find the desired file in the dropdown
Exporting
To handle exporting, there are a few actions to help out:Save: This button is only available when in
Manual
playlist mode. When you click this, it will open a save dialog where you can choose where to output the playlist content into. Once a location is chosen, the data will export and then the playlist will automatically be updated with the reference to that file in the importTextAsset
field.Copy: This button will tokenize the playlist information into a string of text and add it to your clipboard. This will allow you to paste it wherever with ease. Dump it to a text file, share it with a friend, append it to an existing playlist file, etc.
Json: This button will serialize the playlist information into a json string and copy it to your clipboard, similar to the Copy action.
Playlist File Formatting (Tokenized)
Here's an example of what the tokenized format looks like:
?@^/#~
My Custom Header
@https://www.youtube.com/watch?v=BHuF3cUf4n8
^https://soundcloud.com/stessieofficial/together
~Stessie - Together
This song is pretty cool.
@https://www.youtube.com/watch?v=gyR9bdqsv_4
#music,melodic,bouncy,upbeat
~Stessie - Close To You
A classy song deserves a classy description.
Don't ya think?
@https://www.youtube.com/watch?v=JWP5e6u4ryE
/Assets/CustomImages/stessie.candy.heart.png
~Stessie ; BLOOD CODE - Candy Heart
The playlist file format is defined as follows:
- Optional definition of the line-item prefix symbols. It MUST be the first non-whitespace character in the playlist file, anywhere else is undefined behavior.
This is very uncommonly used, but was a special feature request so it's supported. The?
prefix signals that this line defines custom prefix symbols. The rest of the symbols are 1 context per character. The default contexts are listed in the order (after the?
):1. Default is `@`. The symbol used to detect each unique entry in the file.
Every time a line starts with this, the parser assumes that a new playlist entry is to follow.
This also serves as the entry's primary url (aka `Main Url`) line.
2. Default is `^`. Prefix symbol to denote the secondary url (aka `Alternate Url`) line.
3. Default is `/`. Prefix symbol to denote the image path associated with the entry.
This path must be relative to the project root.
(Commonly in the Assets folder, but not required. More info below.)
4. Default is `#`. Prefix symbol to denote the comma separated list of tags.
5. Default is `~`. Prefix symbol to denote the title text of the entry.
The remainder of this document will refer to each context by their default value as defined above. Should you redefine the symbols for your own playlists, just mentally replace what is referenced with your own symbol defines.
A custom header text that will be used by any UI component with a Header text UI component connected (more info in the PlaylistUI section below). This is arbitrary text that does NOT start with the
@
symbol.Each playlist entry is defined by the at
@
symbol at the start of a line. This is immediately followed by the Main Url for that particular entry.On any of the following lines until the next playlist entry defined by the
@
symbol, a single line of any of the following can optionally be provided:^
An alternate url (see the TV's definition of an alt URL) can be provided.
(See first entry in above example)#
A comma,
separated list of tags can be provided. If you want to use white spaces near the commas in the file, you can. They are automatically sanitized on import.
(See second entry in above example)/
A path to an image can be provided. This must be an image that is relative to the project root folder. The line commonly starts with the/Assets/
prefix. The target image is assumed to be aSprite
image (Texture Type =Sprite (2D and UI)
). Loading the image will fail if it's any other Texture Type. If it was manually typed, double check for typos or image locations that have moved recently. If the playlist was exported, it should already be compatible.
(See third entry in above example)~
A custom title can be provided. This can be any text content you want. To make the title text multiple lines, each new line must start with another title prefix symbol. This is a pretty uncommon use-case, but is supported for those who wish for it.
If any line after the playlist entry
@
line does not start with one of the above prefix tokens (^
,#
,/
,~
) then it will assume that the rest of the content until the next detect playlist entry is part of the entry description and will be greedily added to the description text.
When working with the images for a playlist, you can attach them to a sprite atlas for more performant rendering, but depending on the number of images, it may increase the size of the world beyond a desired size. It can be useful, but be aware. See:
https://docs.unity3d.com/2018.4/Documentation/Manual/SpriteAtlasWorkflow.html
Playlist File Formatting (JSON)
For convenience, the Playlist editor also supports a JSON equivalent of the tokenized file format. This makes it easier for machines to parse and interface with. The Playlist json file extension should still be .playlist
. The parser will detect if it should use JSON or Tokenized formatting automatically.
Here is the example from the previous section, but in JSON format for comparison.
{
"header": "My Custom Header",
"entries": [
{
"mainUrl": "https://www.youtube.com/watch?v=BHuF3cUf4n8",
"alternateUrl": "https://soundcloud.com/stessieofficial/together",
"title": "Stessie - Together",
"description": "This song is pretty cool.",
"tags": "",
"image": ""
},
{
"mainUrl": "https://www.youtube.com/watch?v=gyR9bdqsv_4",
"alternateUrl": "",
"title": "Stessie - Close To You",
"description": "A classy song deserves a classy description.\\nDon't ya think?",
"tags": "music,melodic,bouncy,upbeat",
"image": ""
},
{
"mainUrl": "https://www.youtube.com/watch?v=JWP5e6u4ryE",
"alternateUrl": "",
"title": "Stessie ; BLOOD CODE - Candy Heart",
"description": "",
"tags": "",
"image": "Assets/CustomImages/stessie.candy.heart.png"
},
]
}
Tagging
Playlist tagging is the way to provide extra metadata to an entry without affecting the title. Tags are a comma ,
separated list of values defined by the world creator for each entry. The actual tag values can be anything you want and is useful for searching/filtering entries, but there is a special format use case built-in to facilitate playlist sorting.
Searching
For playlist searching, there is a Prefab available containing two input fields, one for searching titles and one for searching tags. Searching goes by tags first and then filters by title search.
Searching titles is a simple contains check, but searching by tags has some formatting available to customize the search.
The tag search term will be split by a comma ,
symbol first. These are considered OR
statements. Within each OR statement, the sub-term will then be split by a plus +
symbol. These are considered AND
statements.
The search is resolved as such:
- For the current playlist entry...
- For each of the OR statements, evaluate each AND statement.
- An AND statement will resolve to true if the searched tag is present in the tag list for the currently evaluating playlist entry.
- If all AND statements are true, the containing OR statement resolves to true and marks the given playlist entry as
visible
in the search and moves to the next entry. - Otherwise, if any AND statements are false, the OR statement resolves to false and the next OR statement is evaluated.
- If all OR statements resolve to false, the playlist entry is marked as
hidden
in the search results. - Move to next playlist entry.
Here's an example tag search: movie+horror+2000s,tvshow+comedy+1990s
Another thing you can do is disable tag search GameObject and add some buttons that update the tag search input field with a premade search. This is great for doing specific custom category searches.
Finally, all searching is now done ASYNCHRONOUSLY! No more lag when trying to search for things in large playlists! (though it does make it take more time)
Sorting
For playlist sorting, there is also a prefab available that comes with some pre-made sort terms. One thing you'll notice is that the sort term syntax is different than the search term syntax.
The syntax is defined as MODE:PREFIX
. The MODE
is a number from 0 to 5 representing the following:
0
- Reset the sort to the original order that the playlist was in at world load.1
- Sort the playlist into a random order (aka shuffle)2
- Sort the playlist by title in ascending unicode order (aka a-z)3
- Sort the playlist by title in descending unicode order (aka z-a)4
- Sort the playlist by the given tag value in ascending order5
- Sort the playlist by the given tag value in descending order
And the :PREFIX
is a value that is exclusively used by the 4
and 5
modes. It specifies what "category" aka prefix should be used to sort the tags by. This prefix is optionally part of the tags list and is delimited by a colon :
symbol for each desired tag.
So for example, if we wanted to specify a playlist entry has being made in a particular year and belongs to a particular show season, our tags list might look like
year:1994,season:3,1990s,comedy,tvshow,etc
This would enable the entry to be sorted by such a year value. So if multiple entries had a year:
prefix, they would be ordered in the playlist based on that value. One with a year of 1992 would be above one with a year of 1994 for mode 4 and inversely for mode 5.
NOTE: When doing a tag search, the prefix is ignored completely and only looks at the value portion if the prefix is present.
Lastly, similar to searching, all sorting is done asynchronously. This means there won't be any lag, but do be aware that when sorting multiple thousands of items, the sorting logic may run for multiple minutes before completing. Work is ongoing to improve this, but for now just be aware of the general slowness of sorting massive playlists.
PlaylistUI Component
If you don't want to have a UI anywhere, you can just use the Playlist component without any PlaylistUIs.
This component contains the UI rendering logic for the Playlist
component. This separate component allows having multiple copies of the UI exist around the world that all use the same parent playlist data. The notable benefit is for extremely large playlists. Since all URLs must be baked into the world, this allows accessing the same playlist data from wherever in the world without having to have duplicated data sources, keeping the build size down.
UI Components
First is the ScrollView component. This is a ScrollRect that is used during the playlist view rendering. This is required for playlist to know how many entries can be rendered within the visible space.
Next up is the two template references, one is the container, the other is the actual template itself. These come with default references out of the box in the prebuilt plugin prefabs.
There is also an optional header text reference you can provide. This is arbitrary text, typically displayed above the playlist.
Customizing the Layout
You can customize the layout of the playlist quite a bit. The easiest way is to get a playlist prefab in scene, go into its hierarchy to the ScrollView/Viewport/Template
object and fiddle around with that. There are only a few things that is checked for in the template:
- There are 4 GameObjects that are checked for as children of the Template:
1) A GameObjects called
Title
that contains an attachedText
component 2) A GameObjects calledUrl
that contains an attachedText
component 3) A GameObjects calledImage
orPoster
that contains an attachedImage
component 4) A GameObjects that contains an attachedSlider
component (no name requirements) - All of these GameObjects are optional, but at a minimum, the
Title
andSlider
are recommended for a better user experience.
Once you have customized the structure of the template, you can also adjust the layout of the template entirely. The playlist will automatically fill in horizontal space of the viewport with the content.
This can be observed by setting the transform setting Anchors -> Max -> X
to 1 / the number of items per row (for example 1/5, or 0.2). Then click Update Scene
and you will see the playlist switch to a 5 column layout. You can also adjust the template Height
for some layout change as well if you want to display larger entries.
These two Template transform settings Anchors -> Max -> X
and Height
are the primary controls for getting your desired layout in the playlist.