-
Notifications
You must be signed in to change notification settings - Fork 0
/
MainWindow.xaml.cs
459 lines (441 loc) · 18.5 KB
/
MainWindow.xaml.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Text.RegularExpressions;
using Microsoft.Web.WebView2.Core;
namespace YouTubeTracker
{
/// <summary>
/// Interaction logic for class MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
/// <summary>
/// Initializes components and populates ComboBox: <c>playListCB</c>.
/// </summary>
public MainWindow()
{
InitializeComponent();
InitializeWebView2Async();
UpdatePlaylistComboBox();
}
/// <summary>
/// Initializes video player
/// </summary>
private async void InitializeWebView2Async()
{
try
{
await videoWeb.EnsureCoreWebView2Async(null);
}
catch(Exception ex)
{
MessageBox.Show("Error: video player not initialised. Try to lunch in Release with 'just my code' disabled." +
"Exception Message:" + ex.Message);
}
}
/// <summary>
/// Populates ComboBox: <c>playListCB</c> with database playlists' names.
/// </summary>
public void UpdatePlaylistComboBox()
{
var context = App.Context;
var playlist_names = context.DBPlaylists
.ToList()
.Select(p => p.Name)
.ToList();
playlistsCB.ItemsSource = playlist_names;
}
/// <summary>
/// Updates ListBox: <c>videoListBox</c> with given list of videos.
/// </summary>
/// <param name="videos">List of videos</param>
public void UpdateVideoListBox(List<VideoData> videos)
{
videoListBox.Items.Clear();
foreach (var video in videos)
{
videoListBox.Items.Add(new ListBoxItem(video.title, video.thumbnail_url));
}
}
/// <summary>
/// Update TextBlock: <c>playlistInfo</c> with given playlist info.
/// </summary>
/// <param name="playlist_id">Playlist id</param>
public void UpdatePlaylistInfoTextBlock(int playlist_id)
{
var context = App.Context;
if (context.DBVideos.Where(x => x.DBPlaylistID == playlist_id).Any())
{
var duration = context.DBVideos
.Where(x => x.DBPlaylistID == playlist_id)
.Sum(x => x.Duration);
var count = context.DBVideos.
Where(x => x.DBPlaylistID == playlist_id)
.Count();
playlistInfo.Text = "Videos count: " + count.ToString() +
" Playlist duration: " + (duration / 60).ToString() + " min.";
}
else // empty playlist
{
playlistInfo.Text = "Videos count: " + 0.ToString() +
" Playlist duration: " + 0.ToString() + " min.";
}
}
/// <summary>
/// Click logic for button: <c>searchButton</c>.
/// Executes youtube search using search phrase (at least 5 characters)
/// and max results (default 10) specified in app window,
/// then updates ListBox <c>videoListBox</c> with results if search view is selected.
/// Search phrase is read from TextBox: <c>videoPhrase</c>.
/// Max search results is read from TextBox: <c>maxSearchResults</c> or set to 10 if box is empty.
/// Fails and shows adequate message box if search phrase is shorter than 5 characters.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SearchButton_Click(object sender, RoutedEventArgs e)
{
// check if max search reults is given otherwise set to 10
if (!UInt32.TryParse(maxSearchResults.Text, out uint max_results))
{
max_results = 10;
}
// validate search phrase input
if (videoPhrase.Text.Length < 5)
{
MessageBox.Show("Search phrase is too short. Enter a least 5 characters.");
return;
}
// execute youtube search and update ListBox if search view is selected
if (YoutubeTracker.Search(videoPhrase.Text, max_results)
&& searchtRadioButton.IsChecked.Value)
{
UpdateVideoListBox(YoutubeTracker.GetLoadedVideosFromSearch());
}
}
/// <summary>
/// Click logic for button: <c>playButton</c>.
/// Plays a selected video from ListBox in WebBrowser: <c>videoWeb</c>.
/// Fails and shows message box If video is not selected.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PlayButton_Click(object sender, RoutedEventArgs e)
{
// check if video is selected in ListBox
var idx = videoListBox.SelectedIndex;
if (idx == -1)
{
MessageBox.Show("Error: video not selected.");
return;
}
// get list of loaded videos depending on current view
List<VideoData> loaded_videos = new List<VideoData>();
if (searchtRadioButton.IsChecked.Value)
{
loaded_videos = YoutubeTracker.GetLoadedVideosFromSearch();
}
else if (playlistRadioButton.IsChecked.Value)
{
loaded_videos = YoutubeTracker.GetLoadedVideosFromDB();
}
// play youtube video in WebView2
var id = loaded_videos[idx].id;
string html =
"<html><head>" +
" <meta content='chrome=1,IE=Edge' http-equiv='X-UA-Compatible'/>" +
" <iframe src= 'https://www.youtube.com/embed/{0}'" +
" \" width='100%' height='100%' frameborder='0' " +
" allow = \"autoplay; encrypted-media\" allowFullScreen></iframe>" +
" <body style=\"background-color:black;\"></body>" +
"</head></html>";
videoWeb.CoreWebView2.NavigateToString(string.Format(html, id));
}
/// <summary>
/// Click logic for button: <c>addToPlaylistButton</c>.
/// Adds selected video to selected playlist, search view required, updates database.
/// Fails and shows adequate message box if:
/// 1. Video/playlist is not selected.
/// 2. Not in search view.
/// 3. Video is already in playlist.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddToPlaylistButton_Click(object sender, RoutedEventArgs e)
{
// check if in search view
if (playlistRadioButton.IsChecked.Value)
{
MessageBox.Show("Error: can't add video from playlist view." +
" Switch view to search.");
return;
}
// check if video is selected in ListBox
var idx = videoListBox.SelectedIndex;
if (idx == -1)
{
MessageBox.Show("Error: video not selected.");
return;
}
// check if playlist is selected in ComboBox
var selected_playlist = playlistsCB.SelectedItem as string;
if (String.IsNullOrEmpty(selected_playlist))
{
MessageBox.Show("Error: playlist not selected.");
return;
}
// get target playlist and target video's youtube id
var loaded_videos = YoutubeTracker.GetLoadedVideosFromSearch();
var context = App.Context;
var playlist = context.DBPlaylists.Where(x => x.Name == selected_playlist)
.FirstOrDefault();
var yt_id = loaded_videos[idx].id;
// check if video is akready in playlist
if (context.DBVideos
.Where(x => (x.DBPlaylistID == playlist.ID) && (x.YTID == yt_id))
.Any()
)
{
MessageBox.Show("Error: video is already in playlist.");
return;
}
// add video to playlist, database
var video = new DataBase.DBVideo()
{
DBPlaylistID = playlist.ID,
YTID = loaded_videos[idx].id,
Duration = YoutubeTracker.YTDuration2seconds(loaded_videos[idx].duration),
EmbedHTML = loaded_videos[idx].embed_html,
ThumbnailURL = loaded_videos[idx].thumbnail_url,
Title = loaded_videos[idx].title
};
context.DBVideos.Add(video);
context.SaveChanges();
// update ListBox if playlist view is selected
if (playlistRadioButton.IsChecked.Value)
{
YoutubeTracker.LoadVideosFromDB(
context.DBVideos
.Where(x => x.DBPlaylistID == playlist.ID)
.ToList()
);
UpdateVideoListBox(YoutubeTracker.GetLoadedVideosFromDB());
}
// print playlist duration and videos count
UpdatePlaylistInfoTextBlock(playlist.ID);
}
/// <summary>
/// Click logic for button: <c>removeFromPlaylistButton</c>.
/// Remove selected video from selected playlist, playlist view required, updates database.
/// Fails and shows adequate message box if:
/// 1. Video/playlist is not selected.
/// 2. Not in playlist view.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RemoveFromPlaylistButton_Click(object sender, RoutedEventArgs e)
{
// check if video is selected in ListBox
var idx = videoListBox.SelectedIndex;
if (idx == -1)
{
MessageBox.Show("Error: video not selected.");
return;
}
// check if playlist is selected in ListBox
var selected_playlist = playlistsCB.SelectedItem as string;
if (String.IsNullOrEmpty(selected_playlist))
{
MessageBox.Show("Error: playlist not selected.");
return;
}
// check if in playlist view
if (searchtRadioButton.IsChecked.Value)
{
MessageBox.Show("Error: can't remove video from search view." +
" Switch view to playlist.");
return;
}
// remove video from playlist, database
var target_video_ytid = YoutubeTracker.GetLoadedVideosFromDB()[idx].id;
var context = App.Context;
var target_video_in_db = context.DBVideos
.Where(x => x.YTID == target_video_ytid)
.FirstOrDefault();
context.DBVideos.Remove(target_video_in_db);
context.SaveChanges();
// update ListBox
YoutubeTracker.GetLoadedVideosFromDB().RemoveAt(idx);
UpdateVideoListBox(YoutubeTracker.GetLoadedVideosFromDB());
// print playlist duration and videos count
var playlist_id = context.DBPlaylists
.Where(x => x.Name == selected_playlist)
.First()
.ID;
UpdatePlaylistInfoTextBlock(playlist_id);
}
/// <summary>
/// Click logic for button: <c>createPlaylisButton</c>.
/// Adds new playlist, name is read from TextBox: <c>phraseText</c>, updated database.
/// Fails and shows adequate message box if:
/// 1. Playlist name was not given.
/// 2. Playlist with given name exists.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CreatePlaylistButton_Click(object sender, RoutedEventArgs e)
{
// validate given playlist name
var playlist_name = videoPhrase.Text;
if (String.IsNullOrEmpty(playlist_name))
{
MessageBox.Show("Error: invalid playlist name." +
" Enter playlist name in phrase box.");
return;
}
// check if playlist with given name exists
var context = App.Context;
if (context.DBPlaylists.Where( x => x.Name == playlist_name).Any())
{
MessageBox.Show("Error: invalid playlist name." +
" Playlist of given name already exists.");
return;
}
// add playlist to database
context.DBPlaylists.Add(new DataBase.DBPlaylist() { Name = playlist_name });
context.SaveChanges();
// update playlist ComboBox
UpdatePlaylistComboBox();
}
/// <summary>
/// Click logic for button: <c>deletePlaylisButton</c>.
/// Removes selected playlist, updates database.
/// Fails and shows message box if playlist is not selected.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DeletePlaylistButton_Click(object sender, RoutedEventArgs e)
{
// check if playlist is selected
var selected_playlist = playlistsCB.SelectedItem as string;
if (String.IsNullOrEmpty(selected_playlist))
{
MessageBox.Show("Error: playlist not selected.");
return;
}
// delete playlist, update database
var context = App.Context;
var delete_target = context.DBPlaylists
.Where(x => x.Name == selected_playlist)
.FirstOrDefault();
context.DBPlaylists.Remove(delete_target);
context.SaveChanges();
// update playlist ComboBox
UpdatePlaylistComboBox();
}
/// <summary>
/// Input validation for TextBox: <c>maxSearchResults</c>.
/// Allows only numeric values from range [1, 50].
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private new void PreviewTextInput(object sender, TextCompositionEventArgs e)
{
// check if input is numeric
Regex regex = new Regex("[^0-9]+");
e.Handled = maxSearchResults.Text.Length >= 2 || regex.IsMatch(e.Text);
// check if input is in range [1, 50]
if (UInt32.TryParse(maxSearchResults.Text + e.Text, out uint num))
{
if (num >= 50)
{
e.Handled = true;
maxSearchResults.Text = "50";
} else if (num == 0)
{
e.Handled = true;
maxSearchResults.Text = "1";
}
}
}
/// <summary>
/// Check logic for RadioButton: <c>searchRadioButton</c>.
/// Switches view to search.
/// Displays search results in ListBox.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SearchRB_Checked(object sender, RoutedEventArgs e)
{
// show search videos in ListBox
UpdateVideoListBox(YoutubeTracker.GetLoadedVideosFromSearch());
}
/// <summary>
/// Check logic for RadioButton: <c>playlistRadioButton</c>.
/// Switches view to playlist.
/// Displays selected playlist videos in ListBox.
/// Fails and shows message box if playlist is not selected.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PlaylistRB_Checked(object sender, RoutedEventArgs e)
{
// check if playlist is selected
var selected_playlist = playlistsCB.SelectedItem as string;
if (String.IsNullOrEmpty(selected_playlist))
{
MessageBox.Show("Error: playlist not selected.");
playlistRadioButton.IsChecked = false;
searchtRadioButton.IsChecked = true;
return;
}
// load playlist videos
var context = App.Context;
var playlist_id = context.DBPlaylists
.Where(x => x.Name == selected_playlist)
.FirstOrDefault()
.ID;
YoutubeTracker.LoadVideosFromDB(
context.DBVideos
.Where(x => x.DBPlaylistID == playlist_id)
.ToList()
);
// show playlist videos in ListBox
UpdateVideoListBox(YoutubeTracker.GetLoadedVideosFromDB());
}
/// <summary>
/// Change logic for ComboBox: <c>playlistCB</c>.
/// Loads and shows (in playlist view) playlist videos when new playist is selected.
/// Prints playlist videos count and duration in minutes.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PlaylistComboBox_Changed(object sender, SelectionChangedEventArgs e)
{
// load selected playlist videos
var context = App.Context;
var playlist_name = playlistsCB.SelectedItem as string;
if (String.IsNullOrEmpty(playlist_name)) return;
var playlist_id = context.DBPlaylists
.Where(x => x.Name == playlist_name)
.First()
.ID;
// check if in playlist view
if (playlistRadioButton.IsChecked.Value)
{
YoutubeTracker.LoadVideosFromDB(
context.DBVideos
.Where(x => x.DBPlaylistID == playlist_id)
.ToList()
);
// update video ListBox
UpdateVideoListBox(YoutubeTracker.GetLoadedVideosFromDB());
}
// print playlist duration and videos count
UpdatePlaylistInfoTextBlock(playlist_id);
}
}
}