Playnite Forum Post
An extension for Playnite by JosefNemec that hides additional copies of games.
Reordable list of Sources/Libraries that assigns each Source a priority according to their position in the priorites list. Higher position meaning a higher priority (lower value). Duplicate hider will use this priority to compute a score for each copy of a game,
Score(game) = Priority(game.Source) - priorityList.Count * IsInstalled(game)?1:0
and copies are sorted in ascending order by their score. All but the first game are then hidden.
If enabled, keeps the scores updated (and hides games accordingly) when changes to the library are made and hides games automatically when Playnite launches or settings are changed.
The list of games that is checked for duplicats can be filtered by the Indclude Platforms, Exclude Sources and Exclude Categories filters.
Additionally to the aforementioned filters, games in the Ignored Games list are also not considered by DuplicateHider.
To remove entries from the list, select one or more entries and right click to remove them.
Also, enabling the Add manually hidden/revealed Games option will cause games which hidden states are changed outside of DuplicateHider to be added to that list.
If the Show Copies in Game Menu option is enabled, right clicking a game will show other copies of the clicked game in the context menu.
The Display string for other copies is used to generate the string that is used for a game's entry in the context menu.
Variables in the format {Prefix'Variable'Suffix}
are only evaluated to a non-empty string, if Variable
can be evaluated.
If Variable
can be evaluated, the prefix and suffix strings are also shown as is.
If no prefix or suffix is needed, {Prefix'Variable}
, {Variable}
and {Variable'Suffix}
can also be used.
To bring up a list of available variables, right click inside the text box and click on a variable to insert it.
The example above used {Name} [{Installed}{ on 'Source}{, ROM: 'ImageNameNoExt}]
as the display string.
This extension provides a custom UI element that can be intgrated by theme creators. To use it, the Theme you are using needs to support it and the UI Integration option must be enabled. Available starting with Planite 9.
The custom UI element consists of a stack of icons associated with the copys of a game. Clicking on an icon will select this version of the game, double clicking launches it. Slightly grayed out icons indicate that a copy is not installed. An expample is shown above.
The extension comes with a set of predefined icons for common libraries (from https://icon-icons.com/pack/Material-Design/2248, under the Apache 2.0 License), but users can also specify their own. For DuplicateHider to find those icons, they need to be named like the sources in the Priority List, for example Steam.ico
or Ubisoft Connect.png
and then placed into the source_icons folder that can be found by pressing the Open user icon folder button in the plugin settings.
Under Extensions -> DuplicateHider functions to manually hide and reveal duplicates can be found. Also, currently selected games can either be added or removed from the Ignore List.
The custom UI element can be intgrated into a Theme by, for example, placing
<ContentControl x:Name="DuplicateHider_SourceSelector" DockPanel.Dock="Right" MaxHeight="{Binding ElementName=PART_ImageIcon, Path=Height}"/>
into the DetailsViewItemTemplate.xaml
file where appropriate. See Playnite documentation for more information. At runtime, Playnite will set its content to a Control holding a StackPanel of icons (ContentControls), depending on the GameContext. This might look like this
when placed in a ListViewItem in the DetailsView. See Playnite Documentation to see where else custom UI elements can be used. Go here for better examples.
There are up to 10 SourceSelectors, DuplicateHider_SourceSelector
, DuplicateHider_SourceSelector1
, DuplicateHider_SourceSelector2
, and so on that you can use by using their names as the name of a ContentControl
in a supported template or view.
For each SourceSelector, you can provide styles for their StackPanel
and the icons which are just ContentControls
s (with the Icon as its content if no style is provided). The styles need to have the keys DuplicateHider_IconContentControlStyle
and DuplicateHider_IconStackPanelStyle
(or with the added number for the other ones).
SourceSelector utilizes a cache for the UI elements and Icons and is suitable for use in the Item Templates for the GridView and DetailsView.
Note: The icon ui elements are also recycled when a SourceSelector's IsVisible property is false, so when animating the opacity, the Visibility property should be Hidden or Collapsed when the opacity is 0.
Example Styles can be found here. Each Icon ContentControl has a corresponding ListData object set as its DataContext. An overview of available Properties can be found in the next section.
Note:
DuplicateHider_SourceSelectorN
is only registered if eitherDuplicateHider_IconContentControlStyleN
orDuplicateHider_IconStackPanelStyleN
is found.DuplicateHider_SourceSelector
is always registered.
There are also 10 instances of DuplicateHider_ContentControl
(in case you want to use several in the same View), numbered like the SourceSelector. These basically only provide a DataContext and need a Style/Template to do anything. To apply a Style, set it as the Tag of a ContentControl with x:Name="DuplicateHider_ContentControl" (or one of the 9 others):
<Style x:Key="DuplicateHider_ContentControlHeader_Style" TargetType="ContentControl"> ... </Style>
...
<ContentControl x:Name="DuplicateHider_ContentControl" Tag="{DynamicResource DuplicateHider_ContentControlHeader_Style}"/>
The styled ContentControl has access to the following DataContext:
DataContext = {
ListData CurrentGame; // Game currently in view
ObversableCollection<ListData> Games; // Data of copys of current game, including itself
Boolean MoreThanOneCopy; // Games.Count() > 1
Boolean SwitchedGroup; // True iff the newly selected Game
// is not a copy of the previously selected one
}
class ListData {
Playnite.SDK.Models.Game Game;
Boolean IsCurrent; // True if this copy is currently in view.
BitmapImage Icon; // Source Icon
String SourceName; // Source name. Use this rather than Game.Source.Name,
// because Source might be null.
String DisplayString; // Expanded display string as defined in plugin settings.
ICommand LaunchCommand;
ICommand SelectCommand;
ICommand InstallCommand;
ICommand UninstallCommand;
}
The Icons are still cached for this component, but using this in the DetailsViewItemTemplate or GridViewItemTemplate may cause a lot of objects to be created whenever the views are switched or view filters are changed, depending on the used Template.
Example Styles can be found here. A selfcontained example of multiple DuplicateHider_ContentControls in the DetailsViewGameOverview.xaml can be found here. See Example Overview.
Themes can also supply their own source icons, by adding entries to the resource dictionary and adding the icon files into the appropriate folder. The entries need to have the key DuplicateHider_SOURCENAME_Icon
, where SOURCENAME needs to be replaced by the name of the source as seen in the Priority List. For example, if you want to add an icon for Uplay aka Ubisoft Connect, you might add
<BitmapImage x:Key="DuplicateHider_Ubisoft Connect_Icon" UriSource="{ThemeFile 'Images/Icons/ubisoft.png'}" RenderOptions.BitmapScalingMode="Fant"/>
to the Media.xaml
file and place ubisoft.png
into the Image/Icons
folder. A default icon can be specified by giving it the key DuplicateHider_Default_Icon
Note: Theme Icons are disabled by default and need to be enabled in the settings in order for them to be used.
By adding
<sys:Int32 x:Key="DuplicateHider_MaxNumberOfIcons">4</sys:Int32>
to the resource dictionary, a Theme can also specify the maximum number of icons per element. In the example above, it is set to 4, which is also the default if no entry is supplied. Each DuplicateHider_MaxNumberOfIconsN
will apply to both DuplicateHider_SourceSelectorN
and DuplicateHider_ContentControlN
. A value less than 1 means no limit on the number of icons.
File | Description | Preview |
---|---|---|
DetailsView ItemTemplate.xaml |
Places clickable Icons next to the game name in the DetailsView. | |
DetailsView ItemTemplate.xaml |
Similar to above example, but here the icons fade in and out when the mouse is over a ListItem. | |
DetailsView ItemTemplate.xaml |
Similar to above example, but here the width of the StackPanel is also animated such that long game names are pushed away when it appears. | |
DetailsView GameOverview.xaml |
Contains Styles for the DuplicateHider_ContentControl and uses them to display available sources as header and adds an conditional extension to the PlayButton. | |
DuplicateHider ContentControl Style_Examples.xaml |
Two Styles for DuplicateHider_ContentControl. DH_ContentControl_Style contains some animations to indicate the current game. |
DH_ContentControl_Simple_Style: DH_ContentControl_Style: |
DuplicateHider SourceSelector Styles_Example.xaml |
Contains fairly barebones Styles for the DuplicateHider_SourceSelector. Basically the default Styles if none are provided for a SourceSelector. DuplicateHider_IconContentControlStyle for the Icons and DuplicateHider_IconStackPanelStyle for the StackPanel |
|
ListGameItem Template.xaml |
Simple example for the SourceSelector on a game card in a fullscreen theme. |
|
GameDetails.xaml | Example for a DetailsView in a fullscreen theme using DuplicateHider_ContentControl . |
|
DetailsView ItemTemplate.xaml |
Example for SourceSelector in DetailsViewItemTemplate with highlighting and animations revealing the source name on hover. |
Some Themes (Night) showing some possibilites of using the custom ui elements provided by DuplicateHider.
Preview: | View | Preview |
---|---|---|
Desktop - DetailsView (Night) |