Remove unused karaoke text effects and associated code

The KaraokeEffect class has been simplified and unused code related to multi-strategy text effects has been removed. This includes removing LegacyKaraokeEffect, ITextKaraokeEffect and EffectAnimationPart classes, and all associated code for handling these classes. This cleanup reduces complexity and allows for easier maintainability.
This commit is contained in:
Ivandro Jao 2024-03-31 10:46:38 +01:00
parent 79067bcbe0
commit c17b0c1c31
5 changed files with 3 additions and 435 deletions

View File

@ -1,357 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace Nikse.SubtitleEdit.Core.Common
{
public class EffectAnimationPart
{
public EffectAnimationPart()
{
Pre = string.Empty;
Text = string.Empty;
Post = string.Empty;
}
public string Pre { get; set; }
public string Text { get; set; }
public string Post { get; set; }
public Color Color { get; set; }
public string Face { get; set; }
public string Size { get; set; }
public static Color NullColor => Color.FromArgb(0, 254, 1, 198);
public static string ToString(List<EffectAnimationPart> parts)
{
var sb = new StringBuilder();
foreach (var part in parts)
{
sb.Append(part.Pre);
sb.Append(part.Text);
sb.Append(part.Post);
}
return sb.ToString();
}
public static Color GetColorFromFontString(string text, Color defaultColor)
{
var s = text.TrimEnd();
var start = s.IndexOf("<font ", StringComparison.OrdinalIgnoreCase);
if (start >= 0 && s.EndsWith("</font>", StringComparison.OrdinalIgnoreCase))
{
int end = s.IndexOf('>', start);
if (end > 0)
{
string f = s.Substring(start, end - start);
if (f.Contains(" color="))
{
int colorStart = f.IndexOf(" color=", StringComparison.OrdinalIgnoreCase);
if (s.IndexOf('"', colorStart + " color=".Length + 1) > 0)
{
end = s.IndexOf('"', colorStart + " color=".Length + 1);
}
s = s.Substring(colorStart, end - colorStart);
s = s.Replace(" color=", string.Empty);
s = s.Trim('\'').Trim('"').Trim('\'');
try
{
if (s.StartsWith("rgb(", StringComparison.OrdinalIgnoreCase))
{
var arr = s.Remove(0, 4).TrimEnd(')').Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return Color.FromArgb(int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2]));
}
return HtmlUtil.GetColorFromString(s);
}
catch
{
return defaultColor;
}
}
}
}
return defaultColor;
}
public static string GetAttributeFromFontString(string text, string attributeName)
{
var s = text.TrimEnd();
var start = s.IndexOf("<font ", StringComparison.OrdinalIgnoreCase);
if (start >= 0)
{
int end = s.IndexOf('>', start);
if (end > 0)
{
var f = s.Substring(start, end - start);
var tag = $" {attributeName}=";
if (f.Contains(tag))
{
int colorStart = f.IndexOf(tag, StringComparison.OrdinalIgnoreCase);
if (s.IndexOf('"', colorStart + tag.Length + 1) > 0)
{
end = s.IndexOf('"', colorStart + tag.Length + 1);
}
s = s.Substring(colorStart, end - colorStart);
s = s.Replace(tag, string.Empty);
s = s.Trim('\'').Trim('"').Trim('\'');
return s;
}
}
}
return string.Empty;
}
public static List<EffectAnimationPart> MakeBase(string text)
{
var i = 0;
var allowedStartTags = new List<string> { "<i>", "<u>", "<b>", "<font ", "<span " };
var allowedEndTags = new List<string> { "</i>", "</u>", "</b>", "</font>", "</span>" };
var list = new List<EffectAnimationPart>();
EffectAnimationPart p = null;
var color = NullColor;
var face = string.Empty;
var size = string.Empty;
var fontStack = new Stack<EffectAnimationPart>();
while (i < text.Length)
{
var c = text[i];
if (c == '{' && text.Substring(i).StartsWith("{\\") && text.IndexOf('}', i) > 0)
{
var endIndex = text.IndexOf('}', i);
var tag = text.Substring(i, endIndex - i + 1);
i += tag.Length;
if (p == null)
{
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
else if (!string.IsNullOrEmpty(p.Text))
{
list.Add(p);
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
p.Pre += tag;
}
else if (c == '<' && allowedStartTags.Any(a => text.Substring(i).StartsWith(a, StringComparison.OrdinalIgnoreCase)) && text.IndexOf('>', i) > 0)
{
var endIndex = text.IndexOf('>', i);
var tag = text.Substring(i, endIndex - i + 1);
i += tag.Length;
if (p == null)
{
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
else if (!string.IsNullOrEmpty(p.Text))
{
list.Add(p);
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
if (tag.StartsWith("<font", StringComparison.OrdinalIgnoreCase))
{
fontStack.Push(new EffectAnimationPart { Color = color, Face = face, Size = size });
// get color
var tagColor = GetColorFromFontString(tag + "a</font>", NullColor);
if (tagColor != NullColor)
{
p.Color = tagColor;
color = tagColor;
}
// get font name (face)
var fontName = GetAttributeFromFontString(tag, "face");
if (!string.IsNullOrEmpty(fontName))
{
p.Face = fontName;
face = fontName;
}
tag = string.Empty;
}
p.Pre += tag;
}
else if (c == '<' && allowedEndTags.Any(a => text.Substring(i).StartsWith(a, StringComparison.OrdinalIgnoreCase)) && text.IndexOf('>', i) > 0)
{
var endIndex = text.IndexOf('>', i);
var tag = text.Substring(i, endIndex - i + 1);
i += tag.Length;
if (p == null)
{
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
// set color
if (tag == "</font>")
{
if (fontStack.Count > 0)
{
var f = fontStack.Pop();
color = f.Color;
face = f.Face;
size = f.Size;
}
else
{
color = NullColor;
face = string.Empty;
size = string.Empty;
}
}
tag = string.Empty;
p.Post += tag;
}
else if (c == '\r')
{
if (p == null)
{
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
else if (!string.IsNullOrEmpty(p.Text))
{
list.Add(p);
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
p.Text = c.ToString();
i++;
if (i < text.Length && text[i] == '\n') // only take one part for \r\n
{
p.Text += '\n';
i++;
}
}
else
{
if (p == null)
{
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
else if (!string.IsNullOrEmpty(p.Text))
{
list.Add(p);
p = new EffectAnimationPart { Color = color, Face = face, Size = size };
}
p.Text = c.ToString();
i++;
}
}
if (p != null && !string.IsNullOrEmpty(p.Pre + p.Text + p.Post))
{
list.Add(p);
}
return list;
}
public static List<EffectAnimationPart> MakeEffectKaraoke(List<EffectAnimationPart> parts, Color animationColor, int inputLast)
{
if (parts == null || parts.Count == 0)
{
return new List<EffectAnimationPart>();
}
var last = inputLast;
if (last > parts.Count)
{
last = parts.Count - 1;
}
// add karaoke color
var list = new List<EffectAnimationPart>();
for (var index = 0; index < parts.Count; index++)
{
var part = parts[index];
list.Add(new EffectAnimationPart
{
Pre = part.Pre,
Text = part.Text,
Post = part.Post,
Color = index <= last ? animationColor : part.Color,
Face = part.Face,
Size = part.Size,
});
}
var startTagsCount = 0;
var endTagsCount = 0;
for (var index = 0; index < list.Count - 1; index++)
{
var part = list[index];
var next = list[index + 1];
if (index == 0)
{
part.Pre += MakeFontTag(part, ref startTagsCount);
if (next.Color != part.Color || next.Face != part.Face || next.Size != part.Size)
{
part.Post = "</font>" + part.Post;
endTagsCount++;
next.Pre += MakeFontTag(next, ref startTagsCount);
}
}
else if (next.Color != part.Color || next.Face != part.Face || next.Size != part.Size)
{
part.Post = "</font>" + part.Post;
endTagsCount++;
next.Pre += MakeFontTag(next, ref startTagsCount);
}
}
if (startTagsCount > endTagsCount)
{
list.Last().Post += "</font>";
}
return list;
}
private static string MakeFontTag(EffectAnimationPart part, ref int startTagsCount)
{
var attributes = string.Empty;
if (part.Color != NullColor)
{
attributes = $" color=\"{ToHtml(part.Color)}\"";
}
if (!string.IsNullOrEmpty(part.Face))
{
attributes += $" face=\"{part.Face}\"";
}
if (!string.IsNullOrEmpty(part.Size))
{
attributes += $" size=\"{part.Size}\"";
}
var result = $"<font{attributes.TrimEnd()}>".Replace("<font>", string.Empty);
if (result.Length > 0)
{
startTagsCount++;
}
return result;
}
public static string ToHtml(Color c)
{
return $"#{c.A:X2}{c.R:X2}{c.G:X2}{c.B:X2}";
}
}
}

View File

@ -1,10 +0,0 @@
using System.Collections.Generic;
using System.Drawing;
namespace Nikse.SubtitleEdit.Core.Common.TextEffect
{
public interface ITextKaraokeEffect
{
IEnumerable<Paragraph> Transform(Paragraph paragraph, Color color, double delay);
}
}

View File

@ -3,7 +3,7 @@ using System.Drawing;
namespace Nikse.SubtitleEdit.Core.Common.TextEffect
{
public class KaraokeEffect : ITextKaraokeEffect
public class KaraokeEffect
{
private readonly TextEffectBase _splitStrategy;

View File

@ -1,30 +0,0 @@
using System.Collections.Generic;
using System.Drawing;
namespace Nikse.SubtitleEdit.Core.Common.TextEffect
{
public class LegacyKaraokeEffect : ITextKaraokeEffect
{
public IEnumerable<Paragraph> Transform(Paragraph paragraph, Color color, double delay)
{
var result = new List<Paragraph>();
var duration = paragraph.DurationTotalMilliseconds - delay;
var partsBase = EffectAnimationPart.MakeBase(paragraph.Text);
var stepsLength = duration / partsBase.Count + 1;
for (var index = 0; index <= partsBase.Count; index++)
{
var list = EffectAnimationPart.MakeEffectKaraoke(partsBase, color, index);
var text = EffectAnimationPart.ToString(list);
var startMilliseconds = index * stepsLength;
startMilliseconds += paragraph.StartTime.TotalMilliseconds;
var endMilliseconds = ((index + 1) * stepsLength) - 1;
endMilliseconds += paragraph.StartTime.TotalMilliseconds;
var start = new TimeCode(startMilliseconds);
var end = new TimeCode(endMilliseconds);
result.Add(new Paragraph(start, end, text));
}
return result;
}
}
}

View File

@ -10,20 +10,6 @@ namespace Nikse.SubtitleEdit.Forms
{
public sealed partial class EffectKaraoke : Form
{
private class ComboboxEffectItem
{
private readonly string _name;
public bool IsMultiStrategy { get; }
public ComboboxEffectItem(string name, bool isMultiStrategy = false)
{
_name = name;
IsMultiStrategy = isMultiStrategy;
}
public override string ToString() => _name;
}
private Paragraph _paragraph;
private List<Paragraph> _animation;
private int _timerCount;
@ -42,20 +28,9 @@ namespace Nikse.SubtitleEdit.Forms
buttonOK.Text = LanguageSettings.Current.General.Ok;
buttonCancel.Text = LanguageSettings.Current.General.Cancel;
CreateComboboxItems();
UiUtil.FixLargeFonts(this, buttonOK);
}
private void CreateComboboxItems()
{
comboBoxEffects.BeginUpdate();
comboBoxEffects.Items.Add(new ComboboxEffectItem("Legacy effect"));
comboBoxEffects.Items.Add(new ComboboxEffectItem("New effect", true));
comboBoxEffects.SelectedIndex = 1; // set new as default
comboBoxEffects.EndUpdate();
}
private void FormEffectKaraoke_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
@ -143,7 +118,8 @@ namespace Nikse.SubtitleEdit.Forms
}
var delaySeconds = (double)numericUpDownDelay.Value;
_animation.AddRange(GetSelectedFromCombobox().Transform(_paragraph, panelColor.BackColor, delaySeconds * TimeCode.BaseUnit));
var karaokeEffect = new KaraokeEffect(SelectStrategy());
_animation.AddRange(karaokeEffect.Transform(_paragraph, panelColor.BackColor, delaySeconds * TimeCode.BaseUnit));
// All remaining time should go to the last paragraph.
if (_animation.Count > 0)
@ -152,17 +128,6 @@ namespace Nikse.SubtitleEdit.Forms
}
}
private ITextKaraokeEffect GetSelectedFromCombobox()
{
var comboboxEffectItem = (ComboboxEffectItem)comboBoxEffects.SelectedItem;;
if (comboboxEffectItem.IsMultiStrategy)
{
return new KaraokeEffect(SelectStrategy());
}
return new LegacyKaraokeEffect();
}
private TextEffectBase SelectStrategy()
{
if (radioButtonByCharEffect.Checked)