Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ _ReSharper*/
packages/

# Ignore everything else in release folders
**/bin/[Rr]elease*/
**/bin/[Rr]elease*/

# Ignore Antigravity agent folders
.agent/
2 changes: 1 addition & 1 deletion source/Common/PluginsCommon/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ internal static string GetPathWithoutAllExtensions(string path)
return Regex.Replace(path, @"(\.[A-Za-z0-9]+)+$", "");
}

internal static string Normalize(this string str)
internal static string Satinize(this string str)
{
if (string.IsNullOrEmpty(str))
{
Expand Down
24 changes: 14 additions & 10 deletions source/Common/SteamCommon/Models/SteamAppDetailsResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Playnite.SDK;
using Newtonsoft.Json;
using Playnite.SDK;
using Playnite.SDK.Data;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -73,22 +74,25 @@ public class Screenshot

public class Movie
{
[SerializationPropertyName("id")]
public uint Id { get; set; }
[JsonProperty("id")]
public long Id { get; set; }

[SerializationPropertyName("name")]
[JsonProperty("name")]
public string Name { get; set; }

[SerializationPropertyName("thumbnail")]
[JsonProperty("thumbnail")]
public Uri Thumbnail { get; set; }

[SerializationPropertyName("webm")]
public Mp4 Webm { get; set; }
[JsonProperty("dash_av1")]
public Uri DashAv1 { get; set; }

[SerializationPropertyName("mp4")]
public Mp4 Mp4 { get; set; }
[JsonProperty("dash_h264")]
public Uri DashH264 { get; set; }

[SerializationPropertyName("highlight")]
[JsonProperty("hls_h264")]
public Uri HlsH264 { get; set; }

[JsonProperty("highlight")]
public bool Highlight { get; set; }
}

Expand Down
64 changes: 39 additions & 25 deletions source/Common/SteamCommon/Web.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public static string GetSteamIdFromSearch(string searchTerm, string steamApiCoun
var results = GetSteamSearchResults(normalizedName);
results.ForEach(a => a.Name = a.Name.NormalizeGameName());

var matchingGameName = normalizedName.Normalize();
var exactMatch = results.FirstOrDefault(x => x.Name.Normalize() == matchingGameName);
var matchingGameName = normalizedName.Satinize();
var exactMatch = results.FirstOrDefault(x => x.Name.Satinize() == matchingGameName);
if (!(exactMatch is null))
{
logger.Info($"Found steam id for search {searchTerm} via steam search, Id: {exactMatch.GameId}");
Expand Down Expand Up @@ -60,9 +60,14 @@ public static List<StoreSearchResult> GetSteamSearchResults(string searchTerm, s
}

// Game Data
var title = gameElem.QuerySelector(".title").InnerHtml;
var releaseDate = gameElem.QuerySelector(".search_released").InnerHtml;
var gameId = gameElem.GetAttribute("data-ds-appid");
if (gameId.IsNullOrEmpty())
{
continue;
}

var title = gameElem.QuerySelector(".title")?.InnerHtml ?? string.Empty;
var releaseDate = gameElem.QuerySelector(".search_released")?.InnerHtml ?? string.Empty;

// Prices Data
var discountPercentage = 0;
Expand All @@ -74,18 +79,21 @@ public static List<StoreSearchResult> GetSteamSearchResults(string searchTerm, s
var isFree = false;

var priceData = gameElem.QuerySelector(".search_discount_and_price");
if (!priceData.InnerHtml.IsNullOrWhiteSpace())
if (priceData != null && !priceData.InnerHtml.IsNullOrWhiteSpace())
{
// Game has pricing data
var discountBlock = priceData.QuerySelector(".discount_block");
if (discountBlock.HasAttribute("data-discount"))
if (discountBlock != null)
{
discountPercentage = int.Parse(discountBlock.GetAttribute("data-discount"));
}

if (discountBlock.HasAttribute("data-price-final"))
{
priceFinal = int.Parse(discountBlock.GetAttribute("data-price-final")) * 0.01;
if (discountBlock.HasAttribute("data-discount"))
{
discountPercentage = int.Parse(discountBlock.GetAttribute("data-discount"));
}

if (discountBlock.HasAttribute("data-price-final"))
{
priceFinal = int.Parse(discountBlock.GetAttribute("data-price-final")) * 0.01;
}
}

priceOriginal = GetSearchOriginalPrice(priceFinal, discountPercentage);
Expand All @@ -95,7 +103,9 @@ public static List<StoreSearchResult> GetSteamSearchResults(string searchTerm, s

//Urls
var storeUrl = gameElem.GetAttribute("href");
var capsuleUrl = gameElem.QuerySelector(".search_capsule").Children[0].GetAttribute("src");
var capsuleUrl = gameElem.QuerySelector(".search_capsule")?
.Children.FirstOrDefault()?
.GetAttribute("src");

results.Add(new StoreSearchResult
{
Expand All @@ -119,31 +129,35 @@ public static List<StoreSearchResult> GetSteamSearchResults(string searchTerm, s
return results;
}

private static void GetCurrencyFromSearchPriceDiv(AngleSharp.Dom.IElement priceBlock, out string currency, out bool isReleased, out bool isFree)
private static void GetCurrencyFromSearchPriceDiv(
AngleSharp.Dom.IElement priceBlock,
out string currency,
out bool isReleased,
out bool isFree)
{
currency = GetCurrencyFromPriceString(priceBlock.QuerySelector(".discount_final_price").InnerHtml);
var noDiscount = priceBlock.QuerySelector(".search_discount_block no_discount");
isReleased = false;
isFree = false;

var priceEl = priceBlock.QuerySelector(".discount_final_price");
currency = priceEl != null ? GetCurrencyFromPriceString(priceEl.InnerHtml) : null;

var noDiscount = priceBlock.QuerySelector(".search_discount_block.no_discount");
if (noDiscount != null)
{
// Non discounted item
isReleased = true;
isFree = currency == null;
isFree = currency.IsNullOrEmpty();
return;
}

var discountDiv = priceBlock.QuerySelector(".search_discount_block");
if (discountDiv != null)
if (discountDiv != null && !discountDiv.InnerHtml.IsNullOrEmpty())
{
// Non discounted item
// Discounted item
isReleased = true;
isFree = currency == null;
isFree = currency.IsNullOrEmpty();
return;
}

isReleased = false;
currency = null;
isFree = false;
return;
}

private static string GetCurrencyFromPriceString(string priceString)
Expand Down
166 changes: 166 additions & 0 deletions source/Generic/ExtraMetadataLoader/Controls/FullscreenVideoWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<Window x:Class="EmlFullscreen.FullscreenVideoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStyle="None"
WindowState="Maximized"
AllowsTransparency="False"
Topmost="True"
Background="Black"
KeyDown="Window_KeyDown"
MouseDoubleClick="Window_MouseDoubleClick"
MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Grid>
<MediaElement Name="fsPlayer"
LoadedBehavior="Manual"
ScrubbingEnabled="True"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MediaOpened="FsPlayer_MediaOpened"
MediaEnded="FsPlayer_MediaEnded" />

<!-- Exit fullscreen button overlay -->
<Border HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="20"
Padding="14,6"
Background="#88000000"
CornerRadius="6"
Cursor="Hand"
MouseLeftButtonDown="ExitButton_MouseLeftButtonDown">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Opacity" Value="0.15" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="0.9" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="0.15" Duration="0:0:0.4" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="✕" FontSize="20" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>

<!-- Transport controls bar at the bottom -->
<Border Name="ControlBar"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
Margin="40,0,40,30"
Padding="12,8"
Background="#88000000"
CornerRadius="6"
Cursor="Arrow"
MouseLeftButtonDown="ControlBar_MouseLeftButtonDown">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Opacity" Value="0.15" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="0.9" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="0.15" Duration="0:0:0.4" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>

<DockPanel LastChildFill="True">
<!-- Play/Pause button -->
<Button Name="PlayPauseButton"
DockPanel.Dock="Left"
Click="PlayPauseButton_Click"
Focusable="False"
Foreground="White"
Background="Transparent"
BorderThickness="0"
Padding="4"
Margin="0,0,10,0"
Cursor="Hand"
VerticalAlignment="Center">
<TextBlock Name="PlayPauseIcon"
FontFamily="Segoe MDL2 Assets"
Text="&#xE769;"
FontSize="20" />
</Button>

<!-- Time display -->
<TextBlock Name="TimeDisplay"
DockPanel.Dock="Left"
Foreground="White"
FontSize="13"
VerticalAlignment="Center"
Margin="0,0,12,0"
Text="00:00 / 00:00" />

<!-- Volume controls (right-docked) -->
<Slider Name="VolumeSlider"
Focusable="False"
DockPanel.Dock="Right"
Width="90"
Minimum="0" Maximum="1"
IsSnapToTickEnabled="True"
TickFrequency="0.025"
VerticalAlignment="Center"
Margin="4,0,0,0"
ValueChanged="VolumeSlider_ValueChanged" />

<!-- Mute button -->
<Button Name="MuteButton"
DockPanel.Dock="Right"
Click="MuteButton_Click"
Focusable="False"
Foreground="White"
Background="Transparent"
BorderThickness="0"
Padding="4"
Margin="10,0,0,0"
Cursor="Hand"
VerticalAlignment="Center">
<TextBlock Name="MuteIcon"
FontFamily="Segoe MDL2 Assets"
Text="&#xE767;"
FontSize="18" />
</Button>

<!-- Timeline slider (fills remaining space) -->
<Slider Name="TimelineSlider"
Focusable="False"
Minimum="0"
IsMoveToPointEnabled="True"
VerticalAlignment="Center"
Margin="0,0,10,0"
Thumb.DragStarted="TimelineSlider_DragStarted"
Thumb.DragCompleted="TimelineSlider_DragCompleted"
PreviewMouseUp="TimelineSlider_PreviewMouseUp" />
</DockPanel>
</Border>
</Grid>
</Window>
Loading