Skip to content

Commit 8b74add

Browse files
Add project files.
1 parent 152fab7 commit 8b74add

17 files changed

+842
-0
lines changed

VideoTagPlayer.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.30204.135
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoTagPlayer", "VideoTagPlayer\VideoTagPlayer.csproj", "{E73F3C78-6E45-40B9-B6C7-3A01530ABEB0}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{E73F3C78-6E45-40B9-B6C7-3A01530ABEB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{E73F3C78-6E45-40B9-B6C7-3A01530ABEB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{E73F3C78-6E45-40B9-B6C7-3A01530ABEB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{E73F3C78-6E45-40B9-B6C7-3A01530ABEB0}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {C6534F7A-544D-475C-857A-574CAD45E28D}
24+
EndGlobalSection
25+
EndGlobal

VideoTagPlayer/AddNoteWindow.xaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Window x:Class="VideoTagPlayer.AddNoteWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:local="clr-namespace:VideoTagPlayer"
7+
mc:Ignorable="d"
8+
Title="AddNoteWindow" Height="450" Width="800"
9+
DataContext="{Binding RelativeSource={RelativeSource self}}">
10+
<DockPanel LastChildFill="True">
11+
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
12+
<Label Content="Time: "/>
13+
<Label Content="{Binding Location}"/>
14+
</StackPanel>
15+
<DockPanel DockPanel.Dock="Bottom">
16+
<Button Content="Remove" Click="RemoveButton_Click"/>
17+
<Button Content="Finish" Click="FinishButton_Click"/>
18+
</DockPanel>
19+
<TextBox AcceptsReturn="True" AcceptsTab="True" Text="{Binding TagContent}"></TextBox>
20+
</DockPanel>
21+
</Window>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Linq;
5+
using System.Runtime.CompilerServices;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using System.Windows;
9+
using System.Windows.Controls;
10+
using System.Windows.Data;
11+
using System.Windows.Documents;
12+
using System.Windows.Input;
13+
using System.Windows.Media;
14+
using System.Windows.Media.Imaging;
15+
using System.Windows.Shapes;
16+
using VideoTagPlayer.Models;
17+
18+
namespace VideoTagPlayer
19+
{
20+
/// <summary>
21+
/// Interaction logic for AddNoteWindow.xaml
22+
/// </summary>
23+
public partial class AddNoteWindow : Window, INotifyPropertyChanged
24+
{
25+
#region Properties
26+
public AddNoteWindow(VideoNote note, TimeSpan location)
27+
{
28+
Note = note;
29+
Location = location;
30+
InitializeComponent();
31+
}
32+
public AddNoteWindow(VideoNote note, NoteTag tag)
33+
{
34+
Note = note;
35+
Location = tag.Location;
36+
TagContent = tag.Content;
37+
InitializeComponent();
38+
}
39+
private VideoNote Note;
40+
#endregion
41+
42+
#region View Properties
43+
private TimeSpan _Location;
44+
public TimeSpan Location { get => _Location; set => SetField(ref _Location, value); }
45+
private string _TagContent;
46+
public string TagContent { get => _TagContent; set => SetField(ref _TagContent, value); }
47+
#endregion
48+
49+
#region Data Binding
50+
public event PropertyChangedEventHandler PropertyChanged;
51+
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
52+
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
53+
protected bool SetField<type>(ref type field, type value, [CallerMemberName] string propertyName = null)
54+
{
55+
if (EqualityComparer<type>.Default.Equals(field, value)) return false;
56+
field = value;
57+
NotifyPropertyChanged(propertyName);
58+
return true;
59+
}
60+
61+
#endregion
62+
63+
#region Events
64+
private void RemoveButton_Click(object sender, RoutedEventArgs e)
65+
{
66+
var tag = Note.GetNoteAt(Location);
67+
if(tag != null)
68+
Note.RemoveNote(tag);
69+
}
70+
private void FinishButton_Click(object sender, RoutedEventArgs e)
71+
{
72+
Note.AddNoteAt(Location, TagContent);
73+
this.Close();
74+
}
75+
#endregion
76+
}
77+
}

VideoTagPlayer/App.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
5+
</startup>
6+
</configuration>

VideoTagPlayer/App.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Application x:Class="VideoTagPlayer.App"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:local="clr-namespace:VideoTagPlayer"
5+
StartupUri="MainWindow.xaml">
6+
<Application.Resources>
7+
8+
</Application.Resources>
9+
</Application>

VideoTagPlayer/App.xaml.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Configuration;
4+
using System.Data;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using System.Windows;
8+
9+
namespace VideoTagPlayer
10+
{
11+
/// <summary>
12+
/// Interaction logic for App.xaml
13+
/// </summary>
14+
public partial class App : Application
15+
{
16+
}
17+
}

VideoTagPlayer/CustomCommands.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using System.Windows.Input;
7+
8+
namespace VideoTagPlayer
9+
{
10+
public static class CustomCommands
11+
{
12+
#region UI Commands
13+
public static readonly RoutedUICommand OpenFile = new RoutedUICommand("Open file", "OpenFile", typeof(CustomCommands));
14+
public static readonly RoutedUICommand PlayPause = new RoutedUICommand("Play or pause", "PlayPause", typeof(CustomCommands));
15+
public static readonly RoutedUICommand AddNote = new RoutedUICommand("Add note at current time", "AddNote", typeof(CustomCommands));
16+
#endregion
17+
}
18+
}

VideoTagPlayer/MainWindow.xaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<Window x:Class="VideoTagPlayer.MainWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:local="clr-namespace:VideoTagPlayer"
7+
xmlns:wpf="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF"
8+
mc:Ignorable="d"
9+
Title="Video Tag Player" Height="450" Width="800"
10+
Closing="Window_Closing"
11+
DataContext="{Binding RelativeSource={RelativeSource self}}">
12+
<Window.CommandBindings>
13+
<CommandBinding Command="Open" CanExecute="OpenFileCommand_CanExecute" Executed="OpenFileCommand_Executed"/>
14+
<CommandBinding Command="local:CustomCommands.PlayPause" CanExecute="PlayPauseCommand_CanExecute" Executed="PlayPauseCommand_Executed"/>
15+
<CommandBinding Command="local:CustomCommands.AddNote" CanExecute="AddNoteCommand_CanExecute" Executed="AddNoteCommand_Executed"/>
16+
</Window.CommandBindings>
17+
<Window.InputBindings>
18+
<KeyBinding Key="F1" Command="Open"/>
19+
<KeyBinding Key="Space" Command="local:CustomCommands.PlayPause"/>
20+
<KeyBinding Key="F2" Command="local:CustomCommands.AddNote"/>
21+
</Window.InputBindings>
22+
<Grid>
23+
<wpf:VideoView x:Name="VideoView" Loaded="VideoView_Loaded">
24+
<Grid>
25+
<TextBlock x:Name="IntroTextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="#FFAAAAAA" Visibility="Visible">
26+
F1 to Open File<LineBreak/>
27+
Space to Play/Pause<LineBreak/>
28+
F2 to Add Note at Current Location<LineBreak/>
29+
Tags are automatically saved.
30+
</TextBlock>
31+
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom">
32+
<Label Content="{Binding CurrentTime}"/>
33+
<Button x:Name="OpenTagButton" Content="Open Tag" Visibility="Collapsed" Click="OpenTagButton_Click"/>
34+
</StackPanel>
35+
</Grid>
36+
</wpf:VideoView>
37+
</Grid>
38+
</Window>

VideoTagPlayer/MainWindow.xaml.cs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using LibVLCSharp.Shared;
2+
using Microsoft.Win32;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.ComponentModel;
6+
using System.Linq;
7+
using System.Runtime.CompilerServices;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using System.Windows;
11+
using System.Windows.Controls;
12+
using System.Windows.Data;
13+
using System.Windows.Documents;
14+
using System.Windows.Input;
15+
using System.Windows.Media;
16+
using System.Windows.Media.Imaging;
17+
using System.Windows.Media.TextFormatting;
18+
using System.Windows.Navigation;
19+
using System.Windows.Shapes;
20+
using VideoTagPlayer.Models;
21+
using MediaPlayer = LibVLCSharp.Shared.MediaPlayer;
22+
23+
namespace VideoTagPlayer
24+
{
25+
/// <summary>
26+
/// Interaction logic for MainWindow.xaml
27+
/// </summary>
28+
public partial class MainWindow : Window, INotifyPropertyChanged
29+
{
30+
#region Components
31+
LibVLC _LibVLC;
32+
MediaPlayer _MediaPlayer;
33+
#endregion
34+
35+
#region Construction
36+
public MainWindow()
37+
{
38+
InitializeComponent();
39+
}
40+
#endregion
41+
42+
#region Properties
43+
public VideoNote Note { get; set; }
44+
#endregion
45+
46+
#region View Properties
47+
private TimeSpan _CurrentTime;
48+
public TimeSpan CurrentTime { get => _CurrentTime; set => SetField(ref _CurrentTime, value); }
49+
private NoteTag Tag { get; set; }
50+
#endregion
51+
52+
#region Events
53+
private void VideoView_Loaded(object sender, RoutedEventArgs e)
54+
{
55+
Core.Initialize();
56+
57+
// Initialize components
58+
_LibVLC = new LibVLC();
59+
_MediaPlayer = new MediaPlayer(_LibVLC);
60+
61+
// Setup media player
62+
VideoView.MediaPlayer = _MediaPlayer;
63+
_MediaPlayer.TimeChanged += _MediaPlayer_TimeChanged;
64+
}
65+
66+
private void _MediaPlayer_TimeChanged(object sender, MediaPlayerTimeChangedEventArgs e)
67+
{
68+
CurrentTime = TimeSpan.FromSeconds(_MediaPlayer.Time / 1000);
69+
if(Note != null && Note.GetNoteAt(CurrentTime) != null)
70+
{
71+
Tag = Note.GetNoteAt(CurrentTime);
72+
Dispatcher.Invoke(() => OpenTagButton.Visibility = Visibility.Visible);
73+
}
74+
else
75+
{
76+
Dispatcher.Invoke(() => OpenTagButton.Visibility = Visibility.Collapsed);
77+
}
78+
}
79+
private void Window_Closing(object sender, CancelEventArgs e)
80+
{
81+
if(Note!=null)
82+
Note.Save();
83+
}
84+
private void OpenTagButton_Click(object sender, RoutedEventArgs e)
85+
{
86+
AddNoteWindow noteWindow = new AddNoteWindow(Note, Tag);
87+
noteWindow.Owner = this;
88+
noteWindow.Show();
89+
}
90+
#endregion
91+
92+
#region Commands
93+
private void OpenFileCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
94+
=> e.CanExecute = true;
95+
private void OpenFileCommand_Executed(object sender, ExecutedRoutedEventArgs e)
96+
{
97+
OpenFileDialog dialog = new OpenFileDialog();
98+
if(dialog.ShowDialog() == true)
99+
{
100+
// Initialize note
101+
Note = new VideoNote(dialog.FileName);
102+
// Start play
103+
IntroTextBlock.Visibility = Visibility.Collapsed;
104+
_MediaPlayer.Play(new Media(_LibVLC, new Uri(dialog.FileName)));
105+
}
106+
}
107+
private void PlayPauseCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
108+
=> e.CanExecute = true;
109+
110+
private void PlayPauseCommand_Executed(object sender, ExecutedRoutedEventArgs e)
111+
{
112+
if (_MediaPlayer.IsPlaying)
113+
_MediaPlayer.Pause();
114+
else if(_MediaPlayer.WillPlay)
115+
_MediaPlayer.Play();
116+
}
117+
118+
private void AddNoteCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
119+
=> e.CanExecute = true;
120+
private void AddNoteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
121+
{
122+
if(_MediaPlayer.WillPlay)
123+
{
124+
_MediaPlayer.Pause();
125+
126+
AddNoteWindow noteWindow = new AddNoteWindow(Note, TimeSpan.FromSeconds(_MediaPlayer.Time / 1000));
127+
noteWindow.Owner = this;
128+
noteWindow.Show();
129+
noteWindow.Closed += (o, v) => { _MediaPlayer.Play(); };
130+
}
131+
}
132+
#endregion
133+
134+
#region Data Binding
135+
public event PropertyChangedEventHandler PropertyChanged;
136+
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
137+
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
138+
protected bool SetField<type>(ref type field, type value, [CallerMemberName] string propertyName = null)
139+
{
140+
if (EqualityComparer<type>.Default.Equals(field, value)) return false;
141+
field = value;
142+
NotifyPropertyChanged(propertyName);
143+
return true;
144+
}
145+
#endregion
146+
}
147+
}

0 commit comments

Comments
 (0)