Skip to content

Commit

Permalink
Fix local Stash/XBVR endpoint sometimes not matching media resource url
Browse files Browse the repository at this point in the history
When locally installed Stash/XBVR repository is accessed from remote media source the media resource + server endpoint comparison will fail due to it pointing to localhost
  • Loading branch information
Yoooi0 committed Feb 9, 2024
1 parent 7327df8 commit 5dbb07b
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 32 deletions.
28 changes: 28 additions & 0 deletions Source/MultiFunPlayer/Common/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,34 @@ public static bool IsLocalhost(this EndPoint endpoint)
throw new NotSupportedException($"{endpoint.GetType()} in not supported.");
}

public static IPAddress[] GetAddresses(this EndPoint endpoint)
{
try
{
if (endpoint is IPEndPoint ipEndPoint)
return [ipEndPoint.Address];
if (endpoint is DnsEndPoint dnsEndPoint)
return Dns.GetHostAddresses(dnsEndPoint.Host, dnsEndPoint.AddressFamily);
}
catch { }

return [];
}

public static async ValueTask<IPAddress[]> GetAddressesAsync(this EndPoint endpoint)
{
try
{
if (endpoint is IPEndPoint ipEndPoint)
return [ipEndPoint.Address];
if (endpoint is DnsEndPoint dnsEndPoint)
return await Dns.GetHostAddressesAsync(dnsEndPoint.Host, dnsEndPoint.AddressFamily);
}
catch { }

return [];
}

public static string ToUriString(this EndPoint endpoint)
{
if (endpoint is IPEndPoint ipEndPoint)
Expand Down
20 changes: 20 additions & 0 deletions Source/MultiFunPlayer/Common/Utils/NetUtils.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Text.RegularExpressions;

namespace MultiFunPlayer.Common;
Expand Down Expand Up @@ -44,6 +45,25 @@ public static bool TryParseEndpoint(string endpointString, out EndPoint endpoint
return endpoint != null;
}

public static IEnumerable<IPAddress> GetAllLocalAddresses()
=> NetworkInterface.GetAllNetworkInterfaces()
.Where(i => i.OperationalStatus == OperationalStatus.Up)
.Select(i => i.GetIPProperties())
.SelectMany(p => p.UnicastAddresses)
.Select(a => a.Address);

public static bool IsLocalAddress(EndPoint endpoint)
{
var addresses = GetAllLocalAddresses().ToList();
return endpoint.GetAddresses().Any(addresses.Contains);
}

public static async ValueTask<bool> IsLocalAddressAsync(EndPoint endpoint)
{
var addresses = GetAllLocalAddresses().ToList();
return (await endpoint.GetAddressesAsync()).Any(addresses.Contains);
}

[GeneratedRegex(@"^(?:(?<family>InterNetwork|InterNetworkV6|Unspecified)\/)?(?<ipOrHost>.+):(?<port>\d+)$")]
private static partial Regex EndpointRegex();
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public override async ValueTask<Dictionary<DeviceAxis, IScriptResource>> SearchF
if (ServerBaseUri == null)
return [];

if (!TryGetSceneId(mediaResource, out var sceneId))
var sceneId = await TryGetSceneId(mediaResource);
if (string.IsNullOrWhiteSpace(sceneId))
return [];

Logger.Debug("Found Stash scene id [Id: {0}]", sceneId);
Expand All @@ -52,44 +53,41 @@ public override async ValueTask<Dictionary<DeviceAxis, IScriptResource>> SearchF
return result;
}

private bool TryGetSceneId(MediaResourceInfo mediaResource, out int sceneId)
private async ValueTask<string> TryGetSceneId(MediaResourceInfo mediaResource)
{
sceneId = -1;
if (mediaResource.IsFile)
{
var match = Regex.Match(mediaResource.Name, @"^(?<id>\d+) - .+");
if (!match.Success)
return false;
return null;

sceneId = int.Parse(match.Groups["id"].Value);
return true;
return match.Groups["id"].Value;
}
else if (mediaResource.IsUrl)
{
var mediaResourceUri = new Uri(mediaResource.Path);
if (!string.Equals(mediaResourceUri.Host, ServerBaseUri.Host, StringComparison.OrdinalIgnoreCase))
return false;
{
if (!NetUtils.TryParseEndpoint(ServerBaseUri.Host, out var serverBaseEndoint) || !serverBaseEndoint.IsLocalhost())
return null;
if (!NetUtils.TryParseEndpoint(mediaResourceUri.Host, out var mediaResourceEndpoint) || !await NetUtils.IsLocalAddressAsync(mediaResourceEndpoint))
return null;
}

var pathAndQuery = mediaResourceUri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);

// <endpoint>/res?scene=<sceneId>
var match = Regex.Match(pathAndQuery, @"scene=(?<id>\d+?)(?>$|&)");
if (match.Success)
{
sceneId = int.Parse(match.Groups["id"].Value);
return true;
}
return match.Groups["id"].Value;

// <endpoint>/scene/<sceneId>/stream
match = Regex.Match(pathAndQuery, @"scene\/(?<id>\d+)\/stream");
if (match.Success)
{
sceneId = int.Parse(match.Groups["id"].Value);
return true;
}
return match.Groups["id"].Value;
}

return false;
return null;
}

private bool TryMatchLocal(QueryResponse queryRespone, IEnumerable<DeviceAxis> axes, Dictionary<DeviceAxis, IScriptResource> result, ILocalScriptRepository localRepository)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public override async ValueTask<Dictionary<DeviceAxis, IScriptResource>> SearchF
if (ServerBaseUri == null)
return [];

if (!TryGetSceneId(mediaResource, out var sceneId))
var sceneId = await TryGetSceneId(mediaResource);
if (string.IsNullOrWhiteSpace(sceneId))
return [];

Logger.Debug("Found XBVR scene id [Id: {0}]", sceneId);
Expand All @@ -41,44 +42,41 @@ public override async ValueTask<Dictionary<DeviceAxis, IScriptResource>> SearchF
return result;
}

private bool TryGetSceneId(MediaResourceInfo mediaResource, out object sceneId)
private async ValueTask<string> TryGetSceneId(MediaResourceInfo mediaResource)
{
sceneId = null;
if (mediaResource.IsFile)
{
var match = Regex.Match(mediaResource.Name, @"^(?<id>\d+) - .+");
if (!match.Success)
return false;
return null;

sceneId = match.Groups["id"].Value;
return true;
return match.Groups["id"].Value;
}
else if (mediaResource.IsUrl)
{
var mediaResourceUri = new Uri(mediaResource.Path);
if (!string.Equals(mediaResourceUri.Host, ServerBaseUri.Host, StringComparison.OrdinalIgnoreCase))
return false;
{
if (!NetUtils.TryParseEndpoint(ServerBaseUri.Host, out var serverBaseEndoint) || !serverBaseEndoint.IsLocalhost())
return null;
if (!NetUtils.TryParseEndpoint(mediaResourceUri.Host, out var mediaResourceEndpoint) || !await NetUtils.IsLocalAddressAsync(mediaResourceEndpoint))
return null;
}

var pathAndQuery = mediaResourceUri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);

// <endpoint>/res?scene=<sceneId>
var match = Regex.Match(pathAndQuery, "scene=(?<id>.+?)(?>$|&)");
if (match.Success)
{
sceneId = match.Groups["id"].Value;
return true;
}
return match.Groups["id"].Value;

// <endpoint>/api/dms/file/<fileId>/<sceneId> - <title>
match = Regex.Match(pathAndQuery, @"api\/dms\/file\/\d+\/(?<id>\d+) - .+");
if (match.Success)
{
sceneId = match.Groups["id"].Value;
return true;
}
return match.Groups["id"].Value;
}

return false;
return null;
}

private bool TryMatchLocal(SceneMetadata metadata, IEnumerable<DeviceAxis> axes, Dictionary<DeviceAxis, IScriptResource> result, ILocalScriptRepository localRepository)
Expand Down

0 comments on commit 5dbb07b

Please sign in to comment.