Skip to content

Commit

Permalink
Merge pull request #1 from hostar/photino
Browse files Browse the repository at this point in the history
  • Loading branch information
hostar authored Oct 28, 2024
2 parents 411cc89 + 8d5988b commit 2c96c82
Show file tree
Hide file tree
Showing 93 changed files with 31,352 additions and 1,817 deletions.
11 changes: 11 additions & 0 deletions App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;

using CurlToCSharp.Constants;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CurlToCSharp.Extensions;
using CurlToCSharp.Constants;
using CurlToCSharp.Models;
using CurlToCSharp.Models.Parsing;

namespace CurlToCSharp.Services
namespace m3u8_downloader_photino.Libs.curl
{
public class CommandLineParser : ICommandLineParser
public class CommandLineParser
{
private readonly IEnumerable<ParameterEvaluator> _evaluators;

Expand Down Expand Up @@ -42,7 +44,8 @@ public ConvertResult<CurlOptions> Parse(Span<char> commandLine)
if (commandLine.IsParameter())
{
var parameter = commandLine.ReadParameter();
EvaluateParameter(parameter, ref commandLine, parseResult);
//EvaluateParameter(parameter, ref commandLine, parseResult);
EvaluateParameter2(parameter.ToString(), ref commandLine, parseResult);
}
else
{
Expand Down Expand Up @@ -92,6 +95,21 @@ private void EvaluateParameter(Span<char> parameter, ref Span<char> commandLine,
convertResult.Warnings.Add(Messages.GetParameterIsNotSupported(par));
}

private void EvaluateParameter2(string parameter, ref Span<char> commandLine, ConvertResult<CurlOptions> convertResult)
{
foreach (var evaluator in _evaluators)
{
if (evaluator.CanEvaluate(parameter))
{
evaluator.Evaluate(ref commandLine, convertResult);

return;
}
}

convertResult.Warnings.Add(Messages.GetParameterIsNotSupported(parameter));
}

private void PostParsing(ConvertResult<CurlOptions> result, ParseState state)
{
if (result.Data.Url == null
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public static Span<char> ReadValue(this ref Span<char> commandLine)
return value.UnEscape();
}

public static Span<char> ReadParameter(this ref Span<char> commandLine)
public static Span<char> ReadParameter(this /**/ref/**/ Span<char> commandLine)
{
var indexOfSpace = commandLine.IndexOf(Chars.Space);
if (indexOfSpace == -1)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace m3u8_downloader_avalonia.deps.M3U8parser
namespace m3u8_downloader_photino.Libs
{
// source: https://github.com/ramtinak/SimpleM3U8Parser
public class M3u8Parser
Expand All @@ -15,6 +15,8 @@ public class M3u8Parser

const string MEDIA_PATTERN = @"EXTINF:(?<duration>.*),\n(?<link>(\S+))";

const string MEDIA_INIT = @"#EXT-X-MAP:URI=\""(?<link>(\S+))\""";

const string QUALITY_PATTERN = @"#EXT-X-STREAM-INF.*RESOLUTION=(?<quality>[0-9]+x[0-9]+).*\n(?<link>(\S+))";

static public M3u8MediaContainer Parse(string content)
Expand All @@ -38,22 +40,33 @@ static public M3u8MediaContainer Parse(string content)
{
var path = m.Groups["link"]?.Value;
var quality = m.Groups["quality"]?.Value;
if (!string.IsNullOrEmpty(path) )
if (!string.IsNullOrEmpty(path))
qualityList.Add(new M3u8Quality { Quality = quality, Path = path });
}

string initChunk = "";
foreach (Match m in Regex.Matches(content, MEDIA_INIT))
{
initChunk = m.Groups["link"]?.Value;
break;
}

var durations = mediaList.Select(m => m.Duration).ToArray();
var container = new M3u8MediaContainer
{
Init = initChunk,
Medias = mediaList,
Qualities = qualityList,
Duration = TimeSpan.FromSeconds(durations.Sum())
};

return container;
}
}

public class M3u8MediaContainer
{
public string Init { get; internal set; }
public List<M3u8Media> Medias { get; internal set; } = new List<M3u8Media>();
public List<M3u8Quality> Qualities { get; internal set; } = new List<M3u8Quality>();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
//using Microsoft.UI.Xaml.Input;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using Windows.Foundation;

namespace m3u8_downloader_avalonia.Models
namespace m3u8_downloader_photino.Models
{
public class HeaderView
public class HttpHeaderView
{
public string Name { get; set; }
public string Value { get; set; }
Expand Down
15 changes: 15 additions & 0 deletions Models/Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace m3u8_downloader_photino.Models
{
public class Settings
{
public bool ParallelDownload { get; set; } = false;
public int ParallelDownloadThreadsCount { get; set; } = 5;
public bool SelectFirstQuality { get; set; } = false;
}
}
16 changes: 16 additions & 0 deletions Pages/Counter.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
private int currentCount = 0;

private void IncrementCount()
{
currentCount++;
}
}
55 changes: 55 additions & 0 deletions Pages/FetchData.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
@page "/fetchdata"
@inject HttpClient Http

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}

@code {
private WeatherForecast[] forecasts;

protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
}

public class WeatherForecast
{
public DateTime Date { get; set; }

public int TemperatureC { get; set; }

public string Summary { get; set; }

public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
146 changes: 146 additions & 0 deletions Pages/Index.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
@page "/"

@inject ThemeService themeService
@inject NotificationService notificationService
@inject DialogService dialogService
@inject PhotinoWebViewManager photinoWebViewManager
@inject IJSRuntime jsRuntime

<div style="z-index: 1000; background-color: rgba(0,0,0,0.2); position: absolute; width: 100%; height: @overlayHeight; display: @overlayDisplay">
</div>

<RadzenStack Orientation="Orientation.Vertical" class="px-4">
<div id="headerDiv">
<RadzenPanel AllowCollapse="true" class="rz-my-10 rz-mx-auto" Style="width: 90%;" Collapsed="true">
<HeaderTemplate>
<RadzenText TextStyle="TextStyle.H6" class="rz-display-flex rz-align-items-center rz-m-0">
<b>Import CURL</b>
</RadzenText>
</HeaderTemplate>
<ChildContent>
<RadzenStack Orientation="Orientation.Vertical">
<RadzenTextArea @bind-Value="importCurlTextArea" />
<RadzenButton Text="Import" Click="ImportCurl" />
</RadzenStack>
</ChildContent>
</RadzenPanel>

<RadzenStack Orientation="Orientation.Horizontal">
<RadzenFormField Text="Download file path" Style="width: 75%;">
<RadzenTextBox @bind-Value="@downloadPath" />
</RadzenFormField>
<RadzenFormField Style="width: 25%;">
<RadzenButton Text="Browse" Style="height: 95%" Click="@Browse_SelectDestication" />
</RadzenFormField>
</RadzenStack>

<RadzenFormField Text="URL" Style="width: 100%;">
<RadzenTextBox @bind-Value="@url" />
</RadzenFormField>


<RadzenDataGrid @ref="headersGrid" AllowAlternatingRows="false" AllowFiltering="false" AllowPaging="true" PageSize="5" AllowSorting="true"
Data="@headers" TItem="HttpHeaderView" EditMode="DataGridEditMode.Single" ColumnWidth="200px" RowUpdate="OnUpdateRow">
<HeaderTemplate>
<RadzenButton ButtonStyle="ButtonStyle.Success" Icon="add_circle" Text="Add HTTP header" Click="@InsertHeaderRow" Disabled="@(false)" />
</HeaderTemplate>
<EmptyTemplate></EmptyTemplate>
<Columns>
<RadzenDataGridColumn Property="Name" Title="Name" Width="150px">
<EditTemplate Context="header">
<RadzenTextBox @bind-Value="header.Name" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn Property="Value" Title="Value" Width="150px">
<EditTemplate Context="header">
<RadzenTextBox @bind-Value="header.Value" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn Context="header" Width="100px" Filterable="false" Sortable="false" TextAlign="TextAlign.Right" Frozen="true" FrozenPosition="FrozenColumnPosition.Right">
<Template Context="header">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@(args => EditRow(header))" @onclick:stopPropagation="true" />
<RadzenButton ButtonStyle="ButtonStyle.Danger" Icon="delete" Variant="Variant.Flat" Shade="Shade.Lighter" Size="ButtonSize.Medium"
class="rz-my-1 rz-ms-1" Click="@(args => DeleteRow(header))" @onclick:stopPropagation="true" />
</Template>
<EditTemplate Context="header">
<RadzenButton Icon="check" ButtonStyle="ButtonStyle.Success" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@((args) => SaveRow(header))" aria-label="Save" />
<RadzenButton Icon="close" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium"
class="rz-my-1 rz-ms-1" Click="@((args) => CancelEdit(header))" aria-label="Cancel" />
</EditTemplate>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
</div>
<RadzenButton Text="Download" ButtonStyle="ButtonStyle.Primary" Click="StartDownload" />

<RadzenText>Download progress:</RadzenText>
<RadzenProgressBar Value="DownloadProgressBarValue" />

<RadzenStack Style="max-height: 700px; overflow-y: scroll; max-width: 100%">
@foreach (var line in progressLog)
{
<RadzenRow>
<RadzenText>@line</RadzenText>
</RadzenRow>
}
</RadzenStack>

<RadzenPanel AllowCollapse="true" class="rz-my-10 rz-mx-auto" Style="width: 90%;" Collapsed="true">
<HeaderTemplate>
<RadzenText TextStyle="TextStyle.H6" class="rz-display-flex rz-align-items-center rz-m-0">
<b>Settings</b>
</RadzenText>
</HeaderTemplate>
<ChildContent>
<RadzenStack Orientation="Orientation.Horizontal">
<RadzenCheckBox @bind-Value=@Settings.ParallelDownload Name="CheckBoxParallelDownload" />
<RadzenLabel Text="Download in parallel, " Component="CheckBoxParallelDownload" />
<RadzenText Text="use" />
<RadzenNumeric @bind-Value=@Settings.ParallelDownloadThreadsCount Style="width: 100px;" />
<RadzenText Text="threads" />
</RadzenStack>
<br />
<RadzenCheckBox @bind-Value=@Settings.SelectFirstQuality Name="CheckBoxSelectFirstQuality" />
<RadzenLabel Text="Automatically select first quality if source only contain one" Component="CheckBoxSelectFirstQuality" />
<br />
<RadzenCheckBox @bind-Value=@doNotConnectChunks Visible="false" Name="DoNotConnectChunks" />
<RadzenLabel Text="Do not connect chunks" Visible="false" Component="DoNotConnectChunks" />
</ChildContent>
</RadzenPanel>

</RadzenStack>

<div style="position: absolute; left: 20px; top: 20px; visibility: hidden;">
<RadzenAppearanceToggle />
</div>

<style>
.rz-panel-titlebar {
flex-direction: row-reverse;
justify-content: left;
}
</style>

<script>
function getHeadersHeight() {
return document.getElementById("headerDiv").getBoundingClientRect().height;
}
</script>

@code {
async Task ShowQualityDialog()
{
var result = await dialogService.OpenAsync("Select quality", ds =>
@<RadzenStack Gap="1.5rem">

<RadzenListBox @bind-Value=@selectedQuality Data=@qualities Style="width: 100%; max-width: 400px; height:200px" TextProperty="Quality"
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "select company" }})" />

<RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.SpaceBetween">
<RadzenStack Orientation="Orientation.Horizontal">
<RadzenButton Text="Confirm selection" Click="() => ds.Close(true)" />
</RadzenStack>
</RadzenStack>
</RadzenStack>);
}
}
Loading

0 comments on commit 2c96c82

Please sign in to comment.