Skip to content
Draft
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
129 changes: 129 additions & 0 deletions Screenbox.Core/Helpers/UrlHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Screenbox.Core.Helpers;

public static class UrlHelpers
{
private static readonly HashSet<string> UnsupportedUrlPatterns = new(StringComparer.OrdinalIgnoreCase)
{
"youtube.com",
"youtu.be",
"m.youtube.com",
"www.youtube.com",
"vimeo.com",
"www.vimeo.com",
"twitch.tv",
"www.twitch.tv",
"dailymotion.com",
"www.dailymotion.com",
"facebook.com",
"www.facebook.com",
"instagram.com",
"www.instagram.com",
"tiktok.com",
"www.tiktok.com"
};

private static readonly HashSet<string> SupportedMediaExtensions = new(StringComparer.OrdinalIgnoreCase)
{
".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm", ".m4v", ".mpg", ".mpeg", ".3gp", ".3g2",
".mp3", ".wav", ".wma", ".aac", ".ogg", ".flac", ".m4a", ".opus",
".m3u8", ".m3u", ".ts", ".mts", ".m2ts", ".m2t"
};

/// <summary>
/// Validates if a URL is supported for direct media playback
/// </summary>
/// <param name="uri">The URI to validate</param>
/// <returns>True if the URL appears to be supported for direct playback, false otherwise</returns>
public static bool IsSupportedMediaUrl(Uri uri)
{
if (uri == null || !uri.IsAbsoluteUri)
return false;

// Check if it's a local file URI - always supported if it passes other validations
if (uri.IsFile && uri.IsLoopback)
return true;

// Check against known unsupported streaming platforms
if (IsUnsupportedStreamingUrl(uri))
return false;

// Check if URL has a supported media file extension
if (HasSupportedMediaExtension(uri))
return true;

// Allow HTTP/HTTPS URLs that don't match unsupported patterns
// These might be direct media URLs or streaming URLs that are supported
if (uri.Scheme == "http" || uri.Scheme == "https")
return true;

// For other schemes, be conservative and return false
return false;
}

/// <summary>
/// Checks if the URL matches known unsupported streaming platforms
/// </summary>
/// <param name="uri">The URI to check</param>
/// <returns>True if the URL is from an unsupported streaming platform</returns>
public static bool IsUnsupportedStreamingUrl(Uri uri)
{
if (uri == null || !uri.IsAbsoluteUri)
return false;

string host = uri.Host.ToLowerInvariant();

return UnsupportedUrlPatterns.Any(pattern =>
host.Equals(pattern, StringComparison.OrdinalIgnoreCase) ||
host.EndsWith("." + pattern, StringComparison.OrdinalIgnoreCase));
}

/// <summary>
/// Checks if the URL has a supported media file extension
/// </summary>
/// <param name="uri">The URI to check</param>
/// <returns>True if the URL has a supported media extension</returns>
private static bool HasSupportedMediaExtension(Uri uri)
{
try
{
string path = uri.AbsolutePath;
string extension = Path.GetExtension(path);
return !string.IsNullOrEmpty(extension) && SupportedMediaExtensions.Contains(extension);
}
catch
{
return false;
}
}

/// <summary>
/// Gets a user-friendly error message for unsupported URLs
/// </summary>
/// <param name="uri">The unsupported URI</param>
/// <returns>A descriptive error message</returns>
public static string GetUnsupportedUrlMessage(Uri uri)
{
if (uri == null)
return "Invalid URL provided.";

if (IsUnsupportedStreamingUrl(uri))
{
string host = uri.Host.ToLowerInvariant();
if (host.Contains("youtube"))
return "YouTube URLs are not supported. Please use direct media file URLs instead.";
if (host.Contains("vimeo"))
return "Vimeo URLs are not supported. Please use direct media file URLs instead.";
if (host.Contains("twitch"))
return "Twitch URLs are not supported. Please use direct media file URLs instead.";

return "This streaming platform is not supported. Please use direct media file URLs instead.";
}

return "This URL format is not supported. Please use direct links to media files (MP4, MP3, M3U8, etc.).";
}
}
1 change: 1 addition & 0 deletions Screenbox.Core/Screenbox.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
<Compile Include="Helpers\EnumExtensions.cs" />
<Compile Include="Helpers\FilesHelpers.cs" />
<Compile Include="Helpers\LanguageHelper.cs" />
<Compile Include="Helpers\UrlHelpers.cs" />
<Compile Include="Helpers\LastPositionTracker.cs" />
<Compile Include="Helpers\ListGrouping.cs" />
<Compile Include="Helpers\LivelyWallpaperUtil.cs" />
Expand Down
16 changes: 14 additions & 2 deletions Screenbox.Core/ViewModels/MediaListViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -645,13 +645,25 @@ private async Task<PlaylistCreateResult> CreatePlaylistAsync(Uri uri)
{
MediaViewModel media => media,
StorageFile file => _mediaFactory.GetSingleton(file),
Uri uri => _mediaFactory.GetTransient(uri),
Uri uri when UrlHelpers.IsSupportedMediaUrl(uri) => _mediaFactory.GetTransient(uri),
Uri uri => throw new ArgumentException(UrlHelpers.GetUnsupportedUrlMessage(uri)),
_ => null
};

private async Task EnqueueAndPlay(object value)
{
MediaViewModel? playNext = GetMedia(value);
MediaViewModel? playNext = null;
try
{
playNext = GetMedia(value);
}
catch (ArgumentException ex)
{
// Show error notification for unsupported URLs
Messenger.Send(new ErrorMessage("URL Not Supported", ex.Message));
return;
}

if (playNext != null)
{
Enqueue(new[] { playNext });
Expand Down
17 changes: 16 additions & 1 deletion Screenbox/Controls/OpenUrlDialog.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@
mc:Ignorable="d">

<Grid>
<TextBox x:Name="UrlBox" PlaceholderText="{strings:Resources Key=OpenUrlPlaceholder}" />
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<TextBox x:Name="UrlBox"
Grid.Row="0"
PlaceholderText="{strings:Resources Key=OpenUrlPlaceholder}"
TextChanged="UrlBox_TextChanged" />

<TextBlock x:Name="ErrorMessage"
Grid.Row="1"
Margin="0,8,0,0"
Foreground="{ThemeResource SystemErrorTextColor}"
TextWrapping="Wrap"
Visibility="Collapsed" />
</Grid>
</ContentDialog>
55 changes: 51 additions & 4 deletions Screenbox/Controls/OpenUrlDialog.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

using System;
using System.Threading.Tasks;
using Screenbox.Core.Helpers;
using Screenbox.Helpers;
using Screenbox.Strings;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

Expand All @@ -25,14 +27,59 @@ public OpenUrlDialog()
OpenUrlDialog dialog = new();
ContentDialogResult result = await dialog.ShowAsync();
string url = dialog.UrlBox.Text;
return result == ContentDialogResult.Primary && Uri.TryCreate(url, UriKind.Absolute, out Uri uri)
? uri
: null;

if (result != ContentDialogResult.Primary || !Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
return null;

// The validation is now handled inline during text input
// If we reach here, the URL should be valid
return uri;
}

private bool CanOpen(string url)
{
return Uri.TryCreate(url, UriKind.Absolute, out Uri _);
if (!Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
return false;

// Check if URL is supported
if (!UrlHelpers.IsSupportedMediaUrl(uri))
return false;

return true;
}

private void UrlBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (sender is TextBox textBox)
{
string url = textBox.Text;

// Clear error if text is empty
if (string.IsNullOrWhiteSpace(url))
{
ErrorMessage.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
return;
}

// Validate URL format first
if (!Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
{
ErrorMessage.Text = "Please enter a valid URL.";
ErrorMessage.Visibility = Windows.UI.Xaml.Visibility.Visible;
return;
}

// Validate if URL is supported
if (!UrlHelpers.IsSupportedMediaUrl(uri))
{
ErrorMessage.Text = UrlHelpers.GetUnsupportedUrlMessage(uri);
ErrorMessage.Visibility = Windows.UI.Xaml.Visibility.Visible;
return;
}

// URL is valid and supported
ErrorMessage.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
}
}
}
3 changes: 3 additions & 0 deletions Screenbox/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -947,4 +947,7 @@
<data name="LanguageSystemDefault" xml:space="preserve">
<value>Use system language</value>
</data>
<data name="UnsupportedUrlError" xml:space="preserve">
<value>This URL format is not supported. Please use direct links to media files (MP4, MP3, M3U8, etc.).</value>
</data>
</root>