Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

New Plugin c/o ChatGPT

Aperta
#262 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
25/100
Tipo di issue
Funzionalità
Chiarezza
Da chiarire
Stato di attività
Ferma
Stack tecnologico
csharp
Ambito
desktop, tooling

Direzione di ricerca

Inizia esaminando il codice fornito di ProblemLinePlugin e il relativo riferimento a Nikse.SubtitleEdit.PluginInterface.dll, quindi confronta la sua implementazione di IPlugin con il comportamento di rilevamento dei plugin alla base della sezione Plugins di Subtitle Edit. Determina cosa è necessario affinché il plugin venga visualizzato e se il workflow proposto per la correzione delle righe evidenziate è supportato. Il lavoro è completato quando il plugin viene caricato in Subtitle Edit e può intervenire sulle righe problematiche previste.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

I thought I'd see if I could get ChatGPT to help write a plugin for Subtitle Edit that would allow me to select all highlighted problem lines for targeted correction (a feature I've wanted incorporating into SE for a long time). This would allow, for example, the auto-balancing of only lines deemed to be of excessive length (rather than every single line, as is currently the case).

Unfortunately, I kept hitting a snag seemingly relating to Nikse.SubtitleEdit.PluginInterface.dll (in that the code below would build successfully in Visual Studio but not appear in the SE Plugins section) and ChatGPT could offer no useful advice about how to resolve this issue.

Could anyone who knows anything about Subtitle Edit plugins please take a look at the code below and let me know if it was even anywhere close to working? Possibly this whole endeavour was a waste of time, given that I know nothing about C#, but it seemed worth a try!

using Nikse.SubtitleEdit.PluginInterface;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Text;
using System.Text.RegularExpressions;

namespace SubtitleEdit.ProblemLineHighlighter
{
    public class ProblemLinePlugin : IPlugin
    {
        private Subtitle _subtitle;
        private SubRip _subRipFormat;

        public string Name => "Problem Line Highlighter";
        public string Text => "Highlight problem lines in subtitles";
        public string Version => "1.0";

        public void Initialize()
        {
            _subRipFormat = new SubRip();
            _subtitle = new Subtitle(_subRipFormat);
        }

        public bool DoesShowDialog()
        {
            return true;
        }

        public void ShowDialog()
        {
            MessageBox.Show("Problem Line Highlighter Plugin loaded!");
            // Here you can later add UI or further plugin logic
        }

        // You can expose your subtitle loading logic here, example:
        public void LoadSubtitleFromLines(string[] lines)
        {
            _subtitle.Paragraphs.Clear();
            var listLines = new List<string>(lines);
            _subRipFormat.LoadSubtitle(_subtitle, listLines, "Example.srt");
            _subtitle.Renumber(1);
        }

        public string GetSubtitleText()
        {
            return _subtitle.ToText();
        }
    }

    // Paste your Subtitle, SubRip, Paragraph, TimeCode classes here (internal or public as needed)
    // For brevity, you can keep them as internal classes below the plugin class,
    // or move to separate files as your project grows.

    internal class Paragraph
    {
        public int Number { get; set; }
        public TimeCode StartTime { get; set; }
        public TimeCode EndTime { get; set; }
        public string Text { get; set; }

        public Paragraph()
        {
            Text = string.Empty;
            StartTime = new TimeCode();
            EndTime = new TimeCode();
        }
    }

    internal class TimeCode
    {
        public int Hours { get; set; }
        public int Minutes { get; set; }
        public int Seconds { get; set; }
        public int Milliseconds { get; set; }

        public TimeCode() { }

        public TimeCode(int hours, int minutes, int seconds, int milliseconds)
        {
            Hours = hours;
            Minutes = minutes;
            Seconds = seconds;
            Milliseconds = milliseconds;
        }

        public override string ToString()
        {
            return $"{Hours:D2}:{Minutes:D2}:{Seconds:D2},{Milliseconds:D3}";
        }

        public void AddTime(TimeSpan timeSpan)
        {
            var totalMs = ToTimeSpan().TotalMilliseconds + timeSpan.TotalMilliseconds;
            if (totalMs < 0) totalMs = 0;

            var ts = TimeSpan.FromMilliseconds(totalMs);
            Hours = ts.Hours;
            Minutes = ts.Minutes;
            Seconds = ts.Seconds;
            Milliseconds = ts.Milliseconds;
        }

        public TimeSpan ToTimeSpan()
        {
            return new TimeSpan(0, Hours, Minutes, Seconds, Milliseconds);
        }
    }

    internal class Subtitle
    {
        private List<Paragraph> _paragraphs;
        private readonly SubRip _format;

        public string Header { get; set; }
        public string Footer { get; set; }
        public string FileName { get; set; }
        public bool IsHearingImpaired { get; private set; }
        public List<Paragraph> Paragraphs => _paragraphs;

        public Subtitle(SubRip subrip)
        {
            _paragraphs = new List<Paragraph>();
            FileName = "Untitled";
            _format = subrip;
        }

        public Paragraph GetParagraphOrDefault(int index)
        {
            if (_paragraphs == null || _paragraphs.Count <= index || index < 0)
                return null;
            return _paragraphs[index];
        }

        public string ToText()
        {
            return _format.ToText(this, System.IO.Path.GetFileNameWithoutExtension(FileName));
        }

        public void AddTimeToAllParagraphs(TimeSpan time)
        {
            foreach (var paragraph in Paragraphs)
            {
                paragraph.StartTime.AddTime(time);
                paragraph.EndTime.AddTime(time);
            }
        }

        public void Renumber(int startNumber)
        {
            int num = ((startNumber >= 0) ? startNumber : 0);
            foreach (var paragraph in _paragraphs)
            {
                paragraph.Number = num;
                num++;
            }
        }
    }

    internal class SubRip
    {
        private enum ExpectingLine
        {
            Number,
            TimeCodes,
            Text
        }

        private static Regex RegexTimeCodes = new Regex(@"^\d{1,2}:\d{2}:\d{2}[,.:]\d{1,3}\s*-->\s*\d{1,2}:\d{2}:\d{2}[,.:]\d{1,3}$", RegexOptions.Compiled);

        private ExpectingLine _expecting;
        private Paragraph _paragraph;
        private int _errorCount;

        public string Extension => ".srt";
        public string Name => "SubRip";
        public int ErrorCount => _errorCount;

        public void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName)
        {
            bool flag = false;
            _paragraph = new Paragraph();
            _expecting = ExpectingLine.Number;
            _errorCount = 0;
            subtitle.Paragraphs.Clear();

            for (int i = 0; i < lines.Count; i++)
            {
                string text = lines[i].TrimEnd();
                text = text.Trim('\u007f');
                string next = (i + 1 < lines.Count) ? lines[i + 1] : string.Empty;

                if (_expecting == ExpectingLine.Text && i + 1 < lines.Count && _paragraph != null && !string.IsNullOrEmpty(_paragraph.Text) && int.TryParse(text, out _) && RegexTimeCodes.IsMatch(lines[i + 1]))
                {
                    _errorCount++;
                    ReadLine(subtitle, string.Empty, string.Empty);
                }
                if (_expecting == ExpectingLine.Number && RegexTimeCodes.IsMatch(text))
                {
                    _errorCount++;
                    _expecting = ExpectingLine.TimeCodes;
                    flag = true;
                }
                ReadLine(subtitle, text, next);
            }

            if (_paragraph.Text.Trim().Length > 0)
                subtitle.Paragraphs.Add(_paragraph);

            foreach (var paragraph in subtitle.Paragraphs)
                paragraph.Text = paragraph.Text.Replace(Environment.NewLine + Environment.NewLine, Environment.NewLine);

            if (_errorCount < 100 && flag)
                subtitle.Renumber(1);
        }

        public string ToText(Subtitle subtitle, string title)
        {
            var sb = new StringBuilder();
            foreach (var paragraph in subtitle.Paragraphs)
            {
                var text = paragraph.Text.Replace(Environment.NewLine + Environment.NewLine, Environment.NewLine);
                sb.Append($"{paragraph.Number}\r\n{paragraph.StartTime} --> {paragraph.EndTime}\r\n{text}\r\n\r\n");
            }
            return sb.ToString().Trim();
        }

        private void ReadLine(Subtitle subtitle, string line, string next)
        {
            switch (_expecting)
            {
                case ExpectingLine.Number:
                    if (int.TryParse(line, out int number))
                    {
                        _paragraph.Number = number;
                        _expecting = ExpectingLine.TimeCodes;
                    }
                    else if (line.Trim().Length > 0)
                    {
                        _errorCount++;
                    }
                    break;
                case ExpectingLine.TimeCodes:
                    if (TryReadTimeCodesLine(line, _paragraph))
                    {
                        _paragraph.Text = string.Empty;
                        _expecting = ExpectingLine.Text;
                    }
                    else if (line.Trim().Length > 0)
                    {
                        _errorCount++;
                        _expecting = ExpectingLine.Number;
                    }
                    break;
                case ExpectingLine.Text:
                    if (!string.IsNullOrWhiteSpace(line))
                    {
                        if (_paragraph.Text.Length > 0)
                            _paragraph.Text += Environment.NewLine;

                        _paragraph.Text += line.TrimEnd().Replace(Environment.NewLine + Environment.NewLine, Environment.NewLine);
                    }
                    else if (!string.IsNullOrWhiteSpace(next) && (int.TryParse(next, out _) || RegexTimeCodes.IsMatch(next)))
                    {
                        subtitle.Paragraphs.Add(_paragraph);
                        _paragraph = new Paragraph();
                        _expecting = ExpectingLine.Number;
                    }
                    break;
            }
        }

        private bool TryReadTimeCodesLine(string line, Paragraph paragraph)
        {
            line = line.Replace('،', ',').Replace('\uf7c8', ',').Replace('¡', ',');
            line = line.Replace(" -> ", " --> ").Replace(" - > ", " --> ").Replace(" ->> ", " --> ");
            line = line.Replace(" -- > ", " --> ").Replace(" - -> ", " --> ").Replace(" -->> ", " --> ").Replace(" ---> ", " --> ");

            line = line.Trim();
            line = line.Replace('.', ':');
            line = Regex.Replace(line, @"\s+", " ");

            if (!RegexTimeCodes.IsMatch(line))
                return false;

            string[] parts = line.Split(new[] { ' ', '-', '>', ':', ',' }, StringSplitOptions.RemoveEmptyEntries);
            try
            {
                int h1 = int.Parse(parts[0]);
                int m1 = int.Parse(parts[1]);
                int s1 = int.Parse(parts[2]);
                int ms1 = int.Parse(parts[3]);

                int h2 = int.Parse(parts[4]);
                int m2 = int.Parse(parts[5]);
                int s2 = int.Parse(parts[6]);
                int ms2 = int.Parse(parts[7]);

                paragraph.StartTime = new TimeCode(h1, m1, s1, ms1);
                paragraph.EndTime = new TimeCode(h2, m2, s2, ms2);

                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

Lingua principale
C#
Stelle
138
Fork
48
Merge medio
5m
PR unite (30g)
6

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di SubtitleEdit/plugins

Tutte le issue di SubtitleEdit/plugins

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.