diff --git a/.gitignore b/.gitignore
index 170a2ca..40f9c31 100644
--- a/.gitignore
+++ b/.gitignore
@@ -353,3 +353,4 @@ healthchecksdb
MigrationBackup/
# End of https://www.gitignore.io/api/visualstudio
+.idea/
\ No newline at end of file
diff --git a/ClipChopper.sln b/ClipChopper.sln
deleted file mode 100644
index ccbf842..0000000
--- a/ClipChopper.sln
+++ /dev/null
@@ -1,31 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29709.97
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClipChopper", "ClipChopper\ClipChopper.csproj", "{956CD016-BDC9-4F7A-9D42-3647DBE46A64}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}.Debug|x64.ActiveCfg = Debug|x64
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}.Debug|x64.Build.0 = Debug|x64
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}.Release|Any CPU.Build.0 = Release|Any CPU
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}.Release|x64.ActiveCfg = Release|x64
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}.Release|x64.Build.0 = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {D5421CE1-B974-4F27-83D9-6EACD36B29A4}
- EndGlobalSection
-EndGlobal
diff --git a/ClipChopper/App.config b/ClipChopper/App.config
deleted file mode 100644
index 56efbc7..0000000
--- a/ClipChopper/App.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ClipChopper/App.xaml b/ClipChopper/Applications/ClipChopper.DesktopApp/App.xaml
similarity index 100%
rename from ClipChopper/App.xaml
rename to ClipChopper/Applications/ClipChopper.DesktopApp/App.xaml
diff --git a/ClipChopper/App.xaml.cs b/ClipChopper/Applications/ClipChopper.DesktopApp/App.xaml.cs
similarity index 100%
rename from ClipChopper/App.xaml.cs
rename to ClipChopper/Applications/ClipChopper.DesktopApp/App.xaml.cs
diff --git a/ClipChopper/Applications/ClipChopper.DesktopApp/AudioTrack.cs b/ClipChopper/Applications/ClipChopper.DesktopApp/AudioTrack.cs
new file mode 100644
index 0000000..738012a
--- /dev/null
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/AudioTrack.cs
@@ -0,0 +1,8 @@
+namespace ClipChopper.DesktopApp
+{
+ public sealed class AudioTrack
+ {
+ public string Name { get; set; } = string.Empty;
+ public int StreamIndex { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ClipChopper/Applications/ClipChopper.DesktopApp/ClipChopper.DesktopApp.csproj b/ClipChopper/Applications/ClipChopper.DesktopApp/ClipChopper.DesktopApp.csproj
new file mode 100644
index 0000000..138c277
--- /dev/null
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/ClipChopper.DesktopApp.csproj
@@ -0,0 +1,67 @@
+
+
+ x64
+ 1.1.0
+ Kirichenko Valery
+ ClipChopper
+ 1.1.0
+ ClipChopper
+ ClipChopper
+ Kirichenko Valery
+
+
+ WinExe
+ netcoreapp3.1
+ 8.0
+ true
+ enable
+ CS8600,CS8602,CS8603,CS8618,CS8625
+ ClipChopper
+ icon.ico
+ MinimumRecommendedRules.ruleset
+ app.manifest
+
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ClipChopper/Applications/ClipChopper.DesktopApp/DirectoryItem.cs b/ClipChopper/Applications/ClipChopper.DesktopApp/DirectoryItem.cs
new file mode 100644
index 0000000..0544947
--- /dev/null
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/DirectoryItem.cs
@@ -0,0 +1,20 @@
+namespace ClipChopper.DesktopApp
+{
+ public sealed class DirectoryItem
+ {
+ public string Name { get; set; }
+ public string Path { get; set; }
+
+ public DirectoryItem(string name, string path)
+ {
+ Name = name;
+ Path = path;
+ }
+
+ public DirectoryItem(string path)
+ {
+ Name = System.IO.Path.GetFileName(path);
+ Path = path;
+ }
+ }
+}
diff --git a/ClipChopper/Applications/ClipChopper.DesktopApp/FragmentSelection.cs b/ClipChopper/Applications/ClipChopper.DesktopApp/FragmentSelection.cs
new file mode 100644
index 0000000..df25b44
--- /dev/null
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/FragmentSelection.cs
@@ -0,0 +1,79 @@
+using System;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace ClipChopper.DesktopApp
+{
+ // TODO: use Prism.WPF BindableBase.
+ public sealed class FragmentSelection : INotifyPropertyChanged
+ {
+ private TimeSpan _start;
+ private TimeSpan _stop;
+ private TimeSpan _duration;
+
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ public FragmentSelection(TimeSpan duration)
+ {
+ Duration = duration;
+ Start = TimeSpan.Zero;
+ Stop = duration;
+ }
+
+ public TimeSpan Start
+ {
+ get => _start;
+
+ set
+ {
+ if (value != _start)
+ {
+ _start = value;
+ NotifyPropertyChanged();
+
+ if (Stop <= Start)
+ {
+ Stop = Duration;
+ }
+ }
+ }
+ }
+
+ public TimeSpan Stop
+ {
+ get => _stop;
+
+ set
+ {
+ if (value != _stop)
+ {
+ _stop = value;
+ NotifyPropertyChanged();
+
+ if (Start >= value)
+ {
+ Start = TimeSpan.Zero;
+ }
+ }
+ }
+ }
+
+ private TimeSpan Duration
+ {
+ get => _duration;
+ set
+ {
+ _duration = value;
+ if (Stop > value)
+ {
+ Stop = value;
+ }
+ }
+ }
+ }
+}
diff --git a/ClipChopper/KeyframeProber.cs b/ClipChopper/Applications/ClipChopper.DesktopApp/KeyframeProber.cs
similarity index 57%
rename from ClipChopper/KeyframeProber.cs
rename to ClipChopper/Applications/ClipChopper.DesktopApp/KeyframeProber.cs
index e3ba9c6..3ec3e1e 100644
--- a/ClipChopper/KeyframeProber.cs
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/KeyframeProber.cs
@@ -3,13 +3,17 @@
namespace ClipChopper
{
- static class KeyframeProber
+ internal static class KeyframeProber
{
public static TimeSpan FindClosestKeyframeTime(string filePath, TimeSpan time)
{
var ffprobePath = Unosquare.FFME.Library.FFmpegDirectory + @"\ffprobe.exe";
var keyframe = TimeSpan.Zero;
-
+
+ string args = $"-threads {Environment.ProcessorCount} -select_streams v -skip_frame nokey " +
+ $"-show_frames -print_format csv " +
+ $"-show_entries frame=key_frame,pkt_dts_time \"{filePath}\"";
+
var startInfo = new ProcessStartInfo()
{
RedirectStandardOutput = true,
@@ -17,17 +21,24 @@ public static TimeSpan FindClosestKeyframeTime(string filePath, TimeSpan time)
UseShellExecute = false,
CreateNoWindow = true,
FileName = ffprobePath,
- Arguments = String.Format("-threads {0} -select_streams v -show_frames -print_format csv -show_entries frame=key_frame,pkt_dts_time \"{1}\"", Environment.ProcessorCount, filePath)
+ Arguments = args
};
using (var probe = Process.Start(startInfo))
{
- probe.OutputDataReceived += new DataReceivedEventHandler((s, e) =>
+ Debug.Assert(probe != null, nameof(probe) + " != null");
+ probe.OutputDataReceived += (s, e) =>
{
- if (e.Data == null) return;
+ if (e.Data is null) return;
+
var data = e.Data.Split(',');
- var splitted_time = data[2].Split('.');
- TimeSpan frame = TimeSpan.FromSeconds(Int32.Parse(splitted_time[0])) + TimeSpan.ParseExact(splitted_time[1], "ffffff", System.Globalization.CultureInfo.InvariantCulture);
+ var splittedTime = data[2].Split('.');
+
+ // TODO: move this logic to new function.
+ TimeSpan frame = TimeSpan.FromSeconds(
+ int.Parse(splittedTime[0])) + TimeSpan.ParseExact(splittedTime[1],
+ "ffffff", System.Globalization.CultureInfo.InvariantCulture
+ );
if (data[1] == "1")
{
@@ -40,7 +51,7 @@ public static TimeSpan FindClosestKeyframeTime(string filePath, TimeSpan time)
keyframe = frame;
}
}
- });
+ };
probe.BeginOutputReadLine();
probe.WaitForExit();
}
diff --git a/ClipChopper/MainWindow.xaml b/ClipChopper/Applications/ClipChopper.DesktopApp/MainWindow.xaml
similarity index 82%
rename from ClipChopper/MainWindow.xaml
rename to ClipChopper/Applications/ClipChopper.DesktopApp/MainWindow.xaml
index 63f521d..5293672 100644
--- a/ClipChopper/MainWindow.xaml
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/MainWindow.xaml
@@ -1,4 +1,4 @@
-
+ Title="Clip Chopper"
+ Height="870"
+ Width="1491"
+ WindowStartupLocation="CenterScreen">
-
-
@@ -72,7 +73,11 @@
-
+
-
diff --git a/ClipChopper/Applications/ClipChopper.DesktopApp/MainWindow.xaml.cs b/ClipChopper/Applications/ClipChopper.DesktopApp/MainWindow.xaml.cs
new file mode 100644
index 0000000..5cd4622
--- /dev/null
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/MainWindow.xaml.cs
@@ -0,0 +1,291 @@
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Ookii.Dialogs.Wpf;
+using System.Threading.Tasks;
+
+namespace ClipChopper.DesktopApp
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public sealed partial class MainWindow
+ {
+ private string? _selectedDirectory;
+ private string? _loadedMedia;
+ private FragmentSelection? _fragment;
+ private int _selectedAudioStream;
+ public ObservableCollection AudioTracks { get; } = new ObservableCollection();
+
+ public MainWindow()
+ {
+ InitializeComponent();
+ Media.MediaOpened += Media_MediaOpened;
+ Media.MediaChanging += Media_MediaChanging;
+ }
+
+ private void Media_MediaOpened(object? sender, Unosquare.FFME.Common.MediaOpenedEventArgs e)
+ {
+ var tags = LoadTags();
+ AudioTracks.Clear();
+ var audioStreams = Media.MediaInfo.Streams
+ .Where(kvp => kvp.Value.CodecType == FFmpeg.AutoGen.AVMediaType.AVMEDIA_TYPE_AUDIO)
+ .Select(kvp => kvp.Value);
+ foreach (var stream in audioStreams)
+ {
+ AudioTracks.Add(new AudioTrack
+ {
+ Name = $"Audio #{stream.StreamIndex} - " + tags
+ .Where(tag => tag.Name.Equals($"Track{stream.StreamId}Name")).Select(tag => tag.Value)
+ .DefaultIfEmpty("Untitled").First(),
+ StreamIndex = stream.StreamIndex
+ });
+ }
+
+ AudioTrackSlider.SelectedIndex = 0;
+
+ Debug.WriteLine(e.Info.Duration);
+ Save.IsEnabled = true;
+ _fragment = new FragmentSelection(e.Info.Duration);
+ PositionSlider.SelectionStart = _fragment.Start.TotalSeconds;
+ PositionSlider.SelectionEnd = _fragment.Stop.TotalSeconds;
+ _fragment.PropertyChanged += Fragment_PropertyChanged;
+ }
+
+ private void Fragment_PropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (_fragment is null)
+ {
+ throw new InvalidOperationException("Fragment value is not initialized.");
+ }
+
+ if (StringComparer.OrdinalIgnoreCase.Equals(e.PropertyName, "Start"))
+ {
+ PositionSlider.SelectionStart = _fragment.Start.TotalSeconds;
+ }
+ else
+ {
+ PositionSlider.SelectionEnd = _fragment.Stop.TotalSeconds;
+ }
+ }
+
+ private async void Play_Click(object sender, RoutedEventArgs e)
+ {
+ if (Media.IsPlaying)
+ {
+ await Media.Pause();
+ }
+ else
+ {
+ if (Media.HasMediaEnded)
+ {
+ await Media.Seek(TimeSpan.Zero);
+ }
+ await Media.Play();
+ }
+ }
+
+ private void Pframe_Click(object sender, RoutedEventArgs e)
+ {
+ Media.StepBackward();
+ }
+
+ private void Nframe_Click(object sender, RoutedEventArgs e)
+ {
+ // Don't make a step if current frame is the last one
+ // fixes an issue when StepForward actually moves to a previous key frame
+ if (Media.Position + Media.PositionStep < Media.PlaybackEndTime)
+ {
+ Media.StepForward();
+ }
+ }
+
+ private void SelectDirectory_Click(object sender, RoutedEventArgs e)
+ {
+ var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
+ if (dialog.ShowDialog().GetValueOrDefault())
+ {
+ _selectedDirectory = dialog.SelectedPath;
+
+ // TODO: implement extensions filter, move this to new method.
+ IReadOnlyList files = Directory.GetFiles(_selectedDirectory, "*.*")
+ .Where(s => s.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase) ||
+ s.EndsWith(".mkv", StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ DirectoryList.ItemsSource = Enumerable.Range(0, files.Count)
+ .Select(i => new DirectoryItem(files[i]))
+ .ToList();
+ }
+ }
+
+ private void RefreshDirectory_Click(object sender, RoutedEventArgs e)
+ {
+ if (_selectedDirectory is null) return;
+
+ // TODO: implement extensions filter, move this to new method.
+ List files = Directory.GetFiles(_selectedDirectory, "*.*")
+ .Where(s => s.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase) ||
+ s.EndsWith(".mkv", StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ DirectoryList.ItemsSource =
+ Enumerable.Range(0, files.Count).Select(i => new DirectoryItem(files[i])).ToList();
+ if (_loadedMedia != null)
+ {
+ DirectoryList.SelectedIndex = files.IndexOf(_loadedMedia);
+ }
+ }
+
+ private void Start_Click(object sender, RoutedEventArgs e)
+ {
+ if (_fragment is null) return;
+
+ _fragment.Start = Media.Position;
+ Debug.WriteLine(Media.Position);
+ }
+
+ private void Stop_Click(object sender, RoutedEventArgs e)
+ {
+ if (_fragment is null) return;
+
+ _fragment.Stop = Media.Position;
+ }
+
+ private void DirectoryList_Selected(object sender, SelectionChangedEventArgs args)
+ {
+ if (DirectoryList.SelectedItem is null ||
+ ((DirectoryItem) DirectoryList.SelectedItem).Path == _loadedMedia)
+ {
+ // Do nothing if selection disappeared or selected file was already loaded.
+ return;
+ }
+
+ var selectedFile = (DirectoryItem) DirectoryList.SelectedItem;
+ if (!File.Exists(selectedFile.Path))
+ {
+ ShowMessage($"Could not load non-existent file {selectedFile.Path}");
+ return;
+ }
+
+ Media.Open(new Uri(selectedFile.Path));
+ _loadedMedia = selectedFile.Path;
+ }
+
+ private void Save_Click(object sender, RoutedEventArgs eventArgs)
+ {
+ if (_fragment is null) return;
+
+ if (_loadedMedia is null)
+ {
+ throw new InvalidOperationException("Loaded media value is not initialized.");
+ }
+
+ Debug.WriteLine(Path.GetExtension(_loadedMedia).Substring(1, 3));
+
+ var dialog = new Ookii.Dialogs.Wpf.VistaSaveFileDialog()
+ {
+ AddExtension = true,
+ Filter = "MP4 Files (*.mp4)|*.mp4|MKV Files (*.mkv)|*.mkv",
+ DefaultExt = "mp4",
+ Title = "Save a clip",
+ OverwritePrompt = true,
+ FileName = "Trimmed " + Path.GetFileName(_loadedMedia)
+ };
+
+ if (!dialog.ShowDialog().GetValueOrDefault()) return;
+
+ Console.WriteLine(dialog.FileName);
+ var inputFile = _loadedMedia;
+ var outputFile = dialog.FileName;
+
+ var ffmpegPath = Path.Combine(Unosquare.FFME.Library.FFmpegDirectory, "ffmpeg.exe");
+ var startKeyframe = KeyframeProber.FindClosestKeyframeTime(inputFile, _fragment.Start);
+
+ string args = $"-y -ss {startKeyframe} -i \"{inputFile}\" -map_metadata 0 " +
+ $"-to \"{_fragment.Stop - startKeyframe}\" -c:v copy -c:a copy " +
+ $"-map 0 \"{outputFile}\"";
+
+ var startInfo = new ProcessStartInfo()
+ {
+ RedirectStandardOutput = true,
+ RedirectStandardInput = true,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ FileName = ffmpegPath,
+ Arguments = args
+ };
+
+ using (var ffmpeg = Process.Start(startInfo))
+ {
+ Debug.Assert(ffmpeg != null, nameof(ffmpeg) + " != null");
+ ffmpeg.OutputDataReceived += (s, e) => { Debug.WriteLine(e.Data); };
+ ffmpeg.WaitForExit();
+ }
+
+ ShowMessage("Done");
+ RefreshDirectory_Click(sender, eventArgs);
+ }
+
+ private void Volume_Change(object sender, RoutedPropertyChangedEventArgs eventArgs)
+ {
+ Media.Volume = (Math.Exp(eventArgs.NewValue) - 1) / (Math.E - 1);
+ }
+
+ private void ShowMessage(string message)
+ {
+ if (!TaskDialog.OSSupportsTaskDialogs)
+ {
+ MessageBox.Show(message);
+ return;
+ }
+
+ var dialog = new TaskDialog
+ {
+ WindowTitle = "Clip Chopper",
+ MainInstruction = message,
+ MainIcon = TaskDialogIcon.Information
+ };
+ dialog.Buttons.Add(new TaskDialogButton(ButtonType.Ok));
+ dialog.ShowDialog(this);
+ }
+
+ private List LoadTags()
+ {
+ var etOptions = new NExifTool.ExifToolOptions()
+ {
+ ExifToolPath = AppDomain.CurrentDomain.BaseDirectory + @"\exiftool.exe"
+ };
+ var et = new NExifTool.ExifTool(etOptions);
+ Debug.WriteLine(etOptions.ExifToolPath);
+ Debug.WriteLine(_loadedMedia);
+ var task = Task.Run(async () => await et.GetTagsAsync(_loadedMedia));
+ return task.Result.ToList();
+ }
+
+ private void Media_MediaChanging(object? sender, Unosquare.FFME.Common.MediaOpeningEventArgs e)
+ {
+
+ var audioStream = Media.MediaInfo.Streams
+ .Where(kvp => kvp.Value.CodecType == FFmpeg.AutoGen.AVMediaType.AVMEDIA_TYPE_AUDIO)
+ .Where(kvp => kvp.Value.StreamIndex == _selectedAudioStream)
+ .Select(kvp => kvp.Value);
+
+ e.Options.AudioStream = audioStream.First();
+
+ }
+
+ private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (AudioTrackSlider.SelectedItem == null) return;
+ _selectedAudioStream = ((AudioTrack)AudioTrackSlider.SelectedItem).StreamIndex;
+ Media.ChangeMedia();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ClipChopper/Applications/ClipChopper.DesktopApp/Utilities.cs b/ClipChopper/Applications/ClipChopper.DesktopApp/Utilities.cs
new file mode 100644
index 0000000..b353194
--- /dev/null
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/Utilities.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace ClipChopper
+{
+ internal sealed class TimeSpanToSecondsConverter : IValueConverter
+ {
+ public TimeSpanToSecondsConverter()
+ {
+ }
+
+ #region IValueConverter Implementation
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value switch
+ {
+ TimeSpan span => span.TotalSeconds,
+
+ Duration duration => duration.HasTimeSpan ? duration.TimeSpan.TotalSeconds : 0d,
+
+ _ => 0d
+ };
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter,
+ CultureInfo culture)
+ {
+ if (!(value is double)) return 0d;
+
+ var result = TimeSpan.FromTicks(
+ System.Convert.ToInt64(TimeSpan.TicksPerSecond * (double) value)
+ );
+
+ // Do the conversion from visibility to bool
+ if (targetType == typeof(TimeSpan)) return result;
+
+ // TODO: wrap conversion logic to new class/method.
+ object convertedBack = targetType == typeof(Duration)
+ ? new Duration(result)
+ : Activator.CreateInstance(targetType)
+ ?? throw new InvalidOperationException($"Activator cannot create instance of type {nameof(Duration)}.");
+
+ return convertedBack;
+ }
+
+ #endregion
+ }
+
+ internal sealed class TimeSpanFormatter : IValueConverter
+ {
+ public TimeSpanFormatter()
+ {
+ }
+
+ #region IValueConverter Implementation
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ TimeSpan? p;
+
+ switch (value)
+ {
+ case TimeSpan position:
+ p = position;
+ break;
+
+ case Duration duration when duration.HasTimeSpan:
+ p = duration.TimeSpan;
+ break;
+
+ default:
+ return string.Empty;
+ }
+
+ if (p.Value == TimeSpan.MinValue) return "N/A";
+
+ return $"{(int)p.Value.TotalHours:00}:{p.Value.Minutes:00}:{p.Value.Seconds:00}.{p.Value.Milliseconds:000}";
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/ClipChopper/Applications/ClipChopper.DesktopApp/app.manifest b/ClipChopper/Applications/ClipChopper.DesktopApp/app.manifest
new file mode 100644
index 0000000..88fc4ec
--- /dev/null
+++ b/ClipChopper/Applications/ClipChopper.DesktopApp/app.manifest
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ClipChopper/Applications/ClipChopper.DesktopApp/exiftool.exe b/ClipChopper/Applications/ClipChopper.DesktopApp/exiftool.exe
new file mode 100644
index 0000000..c0e9afd
Binary files /dev/null and b/ClipChopper/Applications/ClipChopper.DesktopApp/exiftool.exe differ
diff --git a/ClipChopper/ffmpeg/avcodec-58.dll b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avcodec-58.dll
similarity index 100%
rename from ClipChopper/ffmpeg/avcodec-58.dll
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avcodec-58.dll
diff --git a/ClipChopper/ffmpeg/avdevice-58.dll b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avdevice-58.dll
similarity index 100%
rename from ClipChopper/ffmpeg/avdevice-58.dll
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avdevice-58.dll
diff --git a/ClipChopper/ffmpeg/avfilter-7.dll b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avfilter-7.dll
similarity index 100%
rename from ClipChopper/ffmpeg/avfilter-7.dll
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avfilter-7.dll
diff --git a/ClipChopper/ffmpeg/avformat-58.dll b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avformat-58.dll
similarity index 100%
rename from ClipChopper/ffmpeg/avformat-58.dll
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avformat-58.dll
diff --git a/ClipChopper/ffmpeg/avutil-56.dll b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avutil-56.dll
similarity index 100%
rename from ClipChopper/ffmpeg/avutil-56.dll
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/avutil-56.dll
diff --git a/ClipChopper/ffmpeg/ffmpeg.exe b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/ffmpeg.exe
similarity index 100%
rename from ClipChopper/ffmpeg/ffmpeg.exe
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/ffmpeg.exe
diff --git a/ClipChopper/ffmpeg/ffplay.exe b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/ffplay.exe
similarity index 100%
rename from ClipChopper/ffmpeg/ffplay.exe
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/ffplay.exe
diff --git a/ClipChopper/ffmpeg/ffprobe.exe b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/ffprobe.exe
similarity index 100%
rename from ClipChopper/ffmpeg/ffprobe.exe
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/ffprobe.exe
diff --git a/ClipChopper/ffmpeg/postproc-55.dll b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/postproc-55.dll
similarity index 100%
rename from ClipChopper/ffmpeg/postproc-55.dll
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/postproc-55.dll
diff --git a/ClipChopper/ffmpeg/swresample-3.dll b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/swresample-3.dll
similarity index 100%
rename from ClipChopper/ffmpeg/swresample-3.dll
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/swresample-3.dll
diff --git a/ClipChopper/ffmpeg/swscale-5.dll b/ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/swscale-5.dll
similarity index 100%
rename from ClipChopper/ffmpeg/swscale-5.dll
rename to ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/swscale-5.dll
diff --git a/ClipChopper/icon.ico b/ClipChopper/Applications/ClipChopper.DesktopApp/icon.ico
similarity index 100%
rename from ClipChopper/icon.ico
rename to ClipChopper/Applications/ClipChopper.DesktopApp/icon.ico
diff --git a/ClipChopper/ClipChopper.csproj b/ClipChopper/ClipChopper.csproj
deleted file mode 100644
index 1f3c476..0000000
--- a/ClipChopper/ClipChopper.csproj
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {956CD016-BDC9-4F7A-9D42-3647DBE46A64}
- WinExe
- ClipChopper
- Clip Chopper
- v4.7.2
- 512
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 4
- true
- true
- publish\
- true
- Disk
- false
- Foreground
- 7
- Days
- false
- false
- true
- 0
- 1.0.0.%2a
- false
- false
- true
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
- true
- bin\x64\Debug\
- DEBUG;TRACE
- full
- x64
- 7.3
- prompt
- MinimumRecommendedRules.ruleset
- true
-
-
- bin\x64\Release\
- TRACE
- true
- pdbonly
- x64
- 7.3
- prompt
- MinimumRecommendedRules.ruleset
- true
-
-
- app.manifest
-
-
- icon.ico
-
-
-
- ..\packages\FFME.Windows.4.2.330\lib\net472\ffme.win.dll
-
-
- ..\packages\FFmpeg.AutoGen.4.2.0\lib\net45\FFmpeg.AutoGen.dll
-
-
- ..\packages\Ookii.Dialogs.Wpf.1.1.0\lib\net45\Ookii.Dialogs.Wpf.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
-
-
-
- MSBuild:Compile
- Designer
-
-
-
-
- MSBuild:Compile
- Designer
-
-
- App.xaml
- Code
-
-
- MainWindow.xaml
- Code
-
-
-
-
- Code
-
-
- True
- True
- Resources.resx
-
-
- True
- Settings.settings
- True
-
-
- ResXFileCodeGenerator
- Resources.Designer.cs
-
-
-
-
- SettingsSingleFileGenerator
- Settings.Designer.cs
-
-
-
-
-
-
-
-
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
-
-
- False
- Microsoft .NET Framework 4.7.2 %28x86 и x64%29
- true
-
-
- False
- .NET Framework 3.5 SP1
- false
-
-
-
-
\ No newline at end of file
diff --git a/ClipChopper/ClipChopper.sln b/ClipChopper/ClipChopper.sln
new file mode 100644
index 0000000..c65cba2
--- /dev/null
+++ b/ClipChopper/ClipChopper.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29709.97
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Applications", "Applications", "{30A9B94B-57FE-4C5D-B493-2E8F2D578AF8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{A4D3BDEB-BB70-46BC-BB8C-B58D71922315}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C2130176-D2F0-44C6-9D32-219B4B626F05}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClipChopper.DesktopApp", "Applications\ClipChopper.DesktopApp\ClipChopper.DesktopApp.csproj", "{72CA55A6-B3C2-4779-818D-CC49758C2A15}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {72CA55A6-B3C2-4779-818D-CC49758C2A15}.Debug|x64.ActiveCfg = Debug|x64
+ {72CA55A6-B3C2-4779-818D-CC49758C2A15}.Debug|x64.Build.0 = Debug|x64
+ {72CA55A6-B3C2-4779-818D-CC49758C2A15}.Release|x64.ActiveCfg = Release|x64
+ {72CA55A6-B3C2-4779-818D-CC49758C2A15}.Release|x64.Build.0 = Release|x64
+ {72CA55A6-B3C2-4779-818D-CC49758C2A15}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {72CA55A6-B3C2-4779-818D-CC49758C2A15} = {30A9B94B-57FE-4C5D-B493-2E8F2D578AF8}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D5421CE1-B974-4F27-83D9-6EACD36B29A4}
+ EndGlobalSection
+EndGlobal
diff --git a/ClipChopper/MainWindow.xaml.cs b/ClipChopper/MainWindow.xaml.cs
deleted file mode 100644
index ee0f8c6..0000000
--- a/ClipChopper/MainWindow.xaml.cs
+++ /dev/null
@@ -1,282 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.IO;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Diagnostics;
-
-namespace ClipChopper
-{
- ///
- /// Логика взаимодействия для MainWindow.xaml
- ///
- public partial class MainWindow : Window
- {
- private string selectedDirectory;
- private string loadedMedia;
- private FragmentSelection fragment;
-
-
- public MainWindow()
- {
- InitializeComponent();
- Media.MediaOpened += Media_MediaOpened;
- }
-
- private void Media_MediaOpened(object sender, Unosquare.FFME.Common.MediaOpenedEventArgs e)
- {
- Console.WriteLine(e.Info.Duration);
- save.IsEnabled = true;
- fragment = new FragmentSelection(e.Info.Duration);
- PositionSlider.SelectionStart = fragment.Start.TotalSeconds;
- PositionSlider.SelectionEnd = fragment.Stop.TotalSeconds;
- fragment.PropertyChanged += Fragment_PropertyChanged;
- }
-
- private void Fragment_PropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- if (e.PropertyName == "Start") PositionSlider.SelectionStart = fragment.Start.TotalSeconds;
- else PositionSlider.SelectionEnd = fragment.Stop.TotalSeconds;
- }
-
- private async void Play_Click(object sender, RoutedEventArgs e)
- {
-
- if (Media.IsPlaying) await Media.Pause();
- else
- {
- if (Media.HasMediaEnded)
- {
- await Media.Seek(TimeSpan.Zero);
- }
- await Media.Play();
- }
- }
-
- private void Pframe_Click(object sender, RoutedEventArgs e)
- {
- Media.StepBackward();
- }
-
- private void Nframe_Click(object sender, RoutedEventArgs e)
- {
- // Don't make a step if current frame is the last one
- // fixes an issue when StepForward actually moves to a previous key frame
- if (Media.Position + Media.PositionStep < Media.PlaybackEndTime)
- Media.StepForward();
- }
-
- private void SelectDirectory_Click(object sender, RoutedEventArgs e)
- {
- var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
- if (dialog.ShowDialog() == true)
- {
- selectedDirectory = dialog.SelectedPath;
- string[] files = Directory.GetFiles(selectedDirectory, "*.*")
- .Where(s => s.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase) || s.EndsWith(".mkv", StringComparison.OrdinalIgnoreCase)).ToArray();
-
- DirectoryList.ItemsSource = Enumerable.Range(0, files.Length).Select(i => new DirectoryItem(files[i])).ToList();
- }
- }
-
- private void RefreshDirectory_Click(object sender, RoutedEventArgs e)
- {
- if (selectedDirectory == null) return;
- string[] files = Directory.GetFiles(selectedDirectory, "*.*")
- .Where(s => s.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase) || s.EndsWith(".mkv", StringComparison.OrdinalIgnoreCase)).ToArray();
-
- DirectoryList.ItemsSource = Enumerable.Range(0, files.Length).Select(i => new DirectoryItem(files[i])).ToList();
- DirectoryList.SelectedIndex = Array.IndexOf(files, loadedMedia);
- }
-
- private void start_Click(object sender, RoutedEventArgs e)
- {
- if (fragment == null) return;
- fragment.Start = Media.Position;
- Console.WriteLine(Media.Position);
- }
-
- private void stop_Click(object sender, RoutedEventArgs e)
- {
- if (fragment == null) return;
- fragment.Stop = Media.Position;
- }
-
- private void DirectoryList_Selected(object sender, SelectionChangedEventArgs args)
- {
- if (DirectoryList.SelectedItem == null || ((DirectoryItem) DirectoryList.SelectedItem).Path == loadedMedia)
- {
- // Do nothing if selection disappeared or selected file is already loaded
- return;
- }
- var selectedFile = (DirectoryItem) DirectoryList.SelectedItem;
- if (!File.Exists(selectedFile.Path))
- {
- MessageBox.Show($"Could not load non-existant file {selectedFile.Path}");
- return;
- }
- Media.Open(new Uri(selectedFile.Path));
- loadedMedia = selectedFile.Path;
-
- }
-
- private void save_Click(object sender, RoutedEventArgs eventArgs)
- {
- if (fragment == null) return;
- Console.WriteLine(Path.GetExtension(loadedMedia).Substring(1, 3));
- var dialog = new Ookii.Dialogs.Wpf.VistaSaveFileDialog()
- {
- AddExtension = true,
- Filter = "MP4 Files (*.mp4)|*.mp4|MKV Files (*.mkv)|*.mkv",
- DefaultExt = "mp4",
- Title = "Save a clip",
- OverwritePrompt = true,
- FileName = "Trimmed " + Path.GetFileName(loadedMedia)
- };
-
- if (dialog.ShowDialog() == true)
- {
- Console.WriteLine(dialog.FileName);
- var inputFile = loadedMedia;
- var outputFile = dialog.FileName;
-
- var ffmpegPath = Unosquare.FFME.Library.FFmpegDirectory + @"\ffmpeg.exe";
- var startKeyframe = KeyframeProber.FindClosestKeyframeTime(inputFile, fragment.Start);
-
- var startInfo = new ProcessStartInfo()
- {
- RedirectStandardOutput = true,
- RedirectStandardInput = true,
- UseShellExecute = false,
- CreateNoWindow = true,
- FileName = ffmpegPath,
- Arguments = String.Format("-ss {0} -i \"{1}\" -map_metadata 0 -to \"{2}\" -c:v copy -c:a copy -map 0 \"{3}\"",
- startKeyframe, inputFile, fragment.Stop - startKeyframe, outputFile)
- };
-
- using (var ffmpeg = Process.Start(startInfo))
- {
- ffmpeg.OutputDataReceived += new DataReceivedEventHandler((s, e) =>
- {
- Console.WriteLine(e.Data);
- });
- ffmpeg.WaitForExit();
- }
- MessageBox.Show("Done");
- }
- }
- }
-
- public class DirectoryItem
- {
- public string Name { get; set; }
- public string Path { get; set; }
-
- public DirectoryItem(string name, string path)
- {
- this.Name = name;
- this.Path = path;
- }
-
- public DirectoryItem(string path)
- {
- this.Name = System.IO.Path.GetFileName(path);
- this.Path = path;
- }
- }
-
- public class FragmentSelection : INotifyPropertyChanged
- {
- private TimeSpan start;
- private TimeSpan stop;
- private TimeSpan duration;
-
- public event PropertyChangedEventHandler PropertyChanged;
-
- private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
- {
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
- }
- }
-
- public FragmentSelection(TimeSpan duration)
- {
- this.Duration = duration;
- this.Start = TimeSpan.Zero;
- this.Stop = duration;
- }
-
- public TimeSpan Start
- {
- get
- {
- return this.start;
- }
-
- set
- {
- if (value != this.start)
- {
- this.start = value;
- NotifyPropertyChanged("Start");
-
- if (this.Stop <= this.Start)
- {
- this.Stop = this.Duration;
- }
- }
- }
- }
-
- public TimeSpan Stop
- {
- get
- {
- return this.stop;
- }
-
- set
- {
- if (value != this.stop)
- {
- this.stop = value;
- NotifyPropertyChanged("Stop");
-
- if (this.Start >= value)
- {
- this.Start = TimeSpan.Zero;
- }
- }
- }
- }
-
- public TimeSpan Duration
- {
- get
- {
- return this.duration;
- }
- set
- {
- this.duration = value;
- if (this.Stop > value)
- {
- this.Stop = value;
- }
- }
- }
- }
-}
diff --git a/ClipChopper/Properties/AssemblyInfo.cs b/ClipChopper/Properties/AssemblyInfo.cs
deleted file mode 100644
index 2c2cd2a..0000000
--- a/ClipChopper/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using System.Reflection;
-using System.Resources;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Windows;
-
-// Общие сведения об этой сборке предоставляются следующим набором
-// набор атрибутов. Измените значения этих атрибутов, чтобы изменить сведения,
-// связанные со сборкой.
-[assembly: AssemblyTitle("ClipChopper")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ClipChopper")]
-[assembly: AssemblyCopyright("Copyright © 2020")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
-// для компонентов COM. Если необходимо обратиться к типу в этой сборке через
-// из модели COM, установите атрибут ComVisible для этого типа в значение true.
-[assembly: ComVisible(false)]
-
-//Чтобы начать создание локализуемых приложений, задайте
-//CultureYouAreCodingWith в файле .csproj
-//в . Например, при использовании английского (США)
-//в своих исходных файлах установите в en-US. Затем отмените преобразование в комментарий
-//атрибута NeutralResourceLanguage ниже. Обновите "en-US" в
-//строка внизу для обеспечения соответствия настройки UICulture в файле проекта.
-
-//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
-
-
-[assembly: ThemeInfo(
- ResourceDictionaryLocation.None, //где расположены словари ресурсов по конкретным тематикам
- //(используется, если ресурс не найден на странице,
- // или в словарях ресурсов приложения)
- ResourceDictionaryLocation.SourceAssembly //где расположен словарь универсальных ресурсов
- //(используется, если ресурс не найден на странице,
- // в приложении или в каких-либо словарях ресурсов для конкретной темы)
-)]
-
-
-// Сведения о версии для сборки включают четыре следующих значения:
-//
-// Основной номер версии
-// Дополнительный номер версии
-// Номер сборки
-// Номер редакции
-//
-// Можно задать все значения или принять номера сборки и редакции по умолчанию
-// используя "*", как показано ниже:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/ClipChopper/Properties/Resources.Designer.cs b/ClipChopper/Properties/Resources.Designer.cs
deleted file mode 100644
index 25d92d2..0000000
--- a/ClipChopper/Properties/Resources.Designer.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// Этот код создан программой.
-// Исполняемая версия:4.0.30319.42000
-//
-// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
-// повторной генерации кода.
-//
-//------------------------------------------------------------------------------
-
-namespace ClipChopper.Properties {
- using System;
-
-
- ///
- /// Класс ресурса со строгой типизацией для поиска локализованных строк и т.д.
- ///
- // Этот класс создан автоматически классом StronglyTypedResourceBuilder
- // с помощью такого средства, как ResGen или Visual Studio.
- // Чтобы добавить или удалить член, измените файл .ResX и снова запустите ResGen
- // с параметром /str или перестройте свой проект VS.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Resources {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Resources() {
- }
-
- ///
- /// Возвращает кэшированный экземпляр ResourceManager, использованный этим классом.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ClipChopper.Properties.Resources", typeof(Resources).Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- ///
- /// Перезаписывает свойство CurrentUICulture текущего потока для всех
- /// обращений к ресурсу с помощью этого класса ресурса со строгой типизацией.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
- }
- }
-}
diff --git a/ClipChopper/Properties/Resources.resx b/ClipChopper/Properties/Resources.resx
deleted file mode 100644
index af7dbeb..0000000
--- a/ClipChopper/Properties/Resources.resx
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
\ No newline at end of file
diff --git a/ClipChopper/Properties/Settings.Designer.cs b/ClipChopper/Properties/Settings.Designer.cs
deleted file mode 100644
index 49417be..0000000
--- a/ClipChopper/Properties/Settings.Designer.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// Этот код создан программой.
-// Исполняемая версия:4.0.30319.42000
-//
-// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
-// повторной генерации кода.
-//
-//------------------------------------------------------------------------------
-
-namespace ClipChopper.Properties {
-
-
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
-
- private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default {
- get {
- return defaultInstance;
- }
- }
- }
-}
diff --git a/ClipChopper/Properties/Settings.settings b/ClipChopper/Properties/Settings.settings
deleted file mode 100644
index 033d7a5..0000000
--- a/ClipChopper/Properties/Settings.settings
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ClipChopper/Utilities.cs b/ClipChopper/Utilities.cs
deleted file mode 100644
index 2fcfabf..0000000
--- a/ClipChopper/Utilities.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Globalization;
-using System.Windows;
-using System.Windows.Data;
-
-namespace ClipChopper
-{
- class TimeSpanToSecondsConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- switch (value)
- {
- case TimeSpan span:
- return span.TotalSeconds;
- case Duration duration:
- return duration.HasTimeSpan ? duration.TimeSpan.TotalSeconds : 0d;
- default:
- return 0d;
- }
- }
-
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (value is double == false) return 0d;
- var result = TimeSpan.FromTicks(System.Convert.ToInt64(TimeSpan.TicksPerSecond * (double)value));
-
- // Do the conversion from visibility to bool
- if (targetType == typeof(TimeSpan)) return result;
- return targetType == typeof(Duration) ?
- new Duration(result) : Activator.CreateInstance(targetType);
- }
- }
-
- class TimeSpanFormatter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- TimeSpan? p;
-
- switch (value)
- {
- case TimeSpan position:
- p = position;
- break;
- case Duration duration when duration.HasTimeSpan:
- p = duration.TimeSpan;
- break;
- default:
- return string.Empty;
- }
-
- if (p.Value == TimeSpan.MinValue)
- return "N/A";
-
- return $"{(int)p.Value.TotalHours:00}:{p.Value.Minutes:00}:{p.Value.Seconds:00}.{p.Value.Milliseconds:000}";
- }
-
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
- throw new NotImplementedException();
- }
-}
diff --git a/ClipChopper/app.manifest b/ClipChopper/app.manifest
deleted file mode 100644
index ed44269..0000000
--- a/ClipChopper/app.manifest
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/ClipChopper/packages.config b/ClipChopper/packages.config
deleted file mode 100644
index 6af1cd8..0000000
--- a/ClipChopper/packages.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file