diff --git a/.gitignore b/.gitignore index dc04692..d16abc4 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,6 @@ __pycache__/ *.xsd.cs /YouTubeProxy/ExternalBin/ffmpeg.exe YouTubeProxy/obj/Debug/YouTubeProxy.csproj.FileListAbsolute.txt +QTConverter/obj/Debug/QTConverter.csproj.FileListAbsolute.txt +BMFF/BMFF/MatrixIO.IO/obj/Debug/MatrixIO.IO.csproj.FileListAbsolute.txt +QTCommon/obj/Debug/QTCommon.csproj.FileListAbsolute.txt diff --git a/68kTubeProxy.sln b/68kTubeProxy.sln index 87138ab..26ab5bb 100644 --- a/68kTubeProxy.sln +++ b/68kTubeProxy.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QTConverter", "QTConverter\QTConverter.csproj", "{A99D53E3-D57C-4059-8AAA-979E2F9E9E1F}" EndProject @@ -13,6 +13,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixIO.IO", "BMFF\BMFF\Ma EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixIO.IO.Bmff", "BMFF\BMFF\MatrixIO.IO.Bmff\MatrixIO.IO.Bmff.csproj", "{4A565C90-1850-4A15-816D-E332981735AB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32Client", "Win32Client\Win32Client.csproj", "{ABEA9A3E-E9B0-417B-8DD1-76865FF57CD5}" + ProjectSection(ProjectDependencies) = postProject + {3782F686-0E09-4E91-94EA-729B09F5CAC4} = {3782F686-0E09-4E91-94EA-729B09F5CAC4} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +44,10 @@ Global {4A565C90-1850-4A15-816D-E332981735AB}.Debug|Any CPU.Build.0 = Debug|Any CPU {4A565C90-1850-4A15-816D-E332981735AB}.Release|Any CPU.ActiveCfg = Release|Any CPU {4A565C90-1850-4A15-816D-E332981735AB}.Release|Any CPU.Build.0 = Release|Any CPU + {ABEA9A3E-E9B0-417B-8DD1-76865FF57CD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABEA9A3E-E9B0-417B-8DD1-76865FF57CD5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABEA9A3E-E9B0-417B-8DD1-76865FF57CD5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABEA9A3E-E9B0-417B-8DD1-76865FF57CD5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Win32Client/App.config b/Win32Client/App.config new file mode 100644 index 0000000..88fa402 --- /dev/null +++ b/Win32Client/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Win32Client/Client/YouTubeProxyClient.cs b/Win32Client/Client/YouTubeProxyClient.cs new file mode 100644 index 0000000..25e2409 --- /dev/null +++ b/Win32Client/Client/YouTubeProxyClient.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using Win32Client.Helpers; +using Win32Client.Models; + +namespace Win32Client.Client +{ + public class YouTubeProxyClient + { + private WebClient client; + const char separator = '|'; + + + + public YouTubeProxyClient(string baseUrl) + { + client = new WebClient(); + client.BaseAddress = baseUrl; + } + + public List Search(string terms) + { + var csvResult = client.DownloadData(string.Format("api/Search/{0}", Uri.EscapeDataString(terms))).MacRomanToString(); + + var results = MacDeserialiser.Deserialize(csvResult); + + return results.ToList(); + } + + public List GetVideo(string videoId, string profile) + { + var csvResult = client.DownloadData(string.Format("api/Video/{0}/?profile={1}", videoId, profile)).MacRomanToString(); + + var results = MacDeserialiser.Deserialize(csvResult); + + return results.ToList(); + } + } +} diff --git a/Win32Client/ClientSettings.cs b/Win32Client/ClientSettings.cs new file mode 100644 index 0000000..6ef5117 --- /dev/null +++ b/Win32Client/ClientSettings.cs @@ -0,0 +1,57 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Win32Client +{ + public class ClientSettings + { + const string SettingsFile = "ClientSettings.json"; + + public static ClientSettings GetSettings() + { + if (File.Exists(SettingsFile)) + { + try + { + return JsonConvert.DeserializeObject(File.ReadAllText(SettingsFile)); + } + catch (Exception ex) + { + // Log it? + } + } + return ClientSettings.DefaultSettings; + } + + + + public static ClientSettings DefaultSettings + { + get + { + return new ClientSettings + { + BaseUrl = "http://localhost:9000/", + Profile = "h263" + }; + } + } + + public string BaseUrl + { + get;set; + } + + public string Profile { get; set; } + + public void SaveSettings() + { + File.WriteAllText(SettingsFile, JsonConvert.SerializeObject(this)); + } + } +} diff --git a/Win32Client/Helpers/ControlHelper.cs b/Win32Client/Helpers/ControlHelper.cs new file mode 100644 index 0000000..b7e47d6 --- /dev/null +++ b/Win32Client/Helpers/ControlHelper.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Win32Client.Helpers +{ + public static class ControlHelper + { + /// + /// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread. + /// + /// + /// + public static void UIThread(this Control @this, Action code) + { + if (@this.InvokeRequired) + { + @this.BeginInvoke(code); + } + else + { + code.Invoke(); + } + } + } +} diff --git a/Win32Client/Helpers/ResultDeserialiser.cs b/Win32Client/Helpers/ResultDeserialiser.cs new file mode 100644 index 0000000..dc15f4a --- /dev/null +++ b/Win32Client/Helpers/ResultDeserialiser.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Win32Client.Helpers +{ + public static class MacDeserialiser + { + const char CsvSeparator = '|'; + + public static IEnumerable Deserialize(string input) + { + var fields = + (from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) + where new[] { MemberTypes.Field, MemberTypes.Property }.Contains(mi.MemberType) + let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute)) + orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name + select mi).ToArray(); + + var lines = input.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + var result = new List(); + foreach (var line in lines) + { + var item = line.Split(CsvSeparator); + var record = (T)Activator.CreateInstance(typeof(T)); + + for (int i = 0; i < fields.Length; i++) + { + var field = fields[i]; + SetValue(field, record, item[i]); + } + result.Add(record); + } + + return result; + } + + private static void SetValue(MemberInfo field, T record, string value) + { + if (field is FieldInfo) + { + var fi = (FieldInfo)field; + fi.SetValue(record, Convert.ChangeType(value, fi.FieldType)); + } + else if (field is PropertyInfo) + { + var pi = (PropertyInfo)field; + if (pi.PropertyType.IsEnum) + pi.SetValue(record, Enum.Parse(pi.PropertyType, value)); + else + pi.SetValue(record, Convert.ChangeType(value, pi.PropertyType)); + } + else + { + throw new Exception("Unhandled case."); + } + } + + } + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class ColumnOrderAttribute : Attribute + { + public int Order { get; private set; } + public ColumnOrderAttribute(int order) { Order = order; } + } +} + diff --git a/Win32Client/Helpers/StringExtensions.cs b/Win32Client/Helpers/StringExtensions.cs new file mode 100644 index 0000000..c31e2d0 --- /dev/null +++ b/Win32Client/Helpers/StringExtensions.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Win32Client.Helpers +{ + public static class StringExtensions + { + /// + /// The Mac Results are in MacRoman encoding, return it back to UTF + /// + /// + /// + public static string MacRomanToString(this byte[] source) + { + return System.Text.Encoding.GetEncoding(10000).GetString(source); + } + + } +} diff --git a/Win32Client/Models/ConversionStatusModel.cs b/Win32Client/Models/ConversionStatusModel.cs new file mode 100644 index 0000000..0e737f9 --- /dev/null +++ b/Win32Client/Models/ConversionStatusModel.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Win32Client.Helpers; + +namespace Win32Client.Models +{ + public class ConversionStatusModel + { + [ColumnOrder(1)] + public string VideoId { get; set; } + + [ColumnOrder(2)] + public StatusCodes Status { get; set; } + + [ColumnOrder(3)] + public string Error { get; set; } + + /// + /// Duration in seconds + /// + [ColumnOrder(4)] + public int Duration { get; set; } + + [ColumnOrder(5)] + public int Progress { get; set; } + + public enum StatusCodes + { + Error, + Encoding, + ReadyForDownload + } + } +} diff --git a/Win32Client/Models/SearchResultModel.cs b/Win32Client/Models/SearchResultModel.cs new file mode 100644 index 0000000..8eed4fc --- /dev/null +++ b/Win32Client/Models/SearchResultModel.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Win32Client.Helpers; + +namespace Win32Client.Models +{ + public class SearchResultModel + { + + [ColumnOrderAttribute(1)] + public string VideoId { get; set; } + + [ColumnOrderAttribute(2)] + public string Title { get; set; } + + [ColumnOrderAttribute(3)] + public string Description { get; set; } + + [ColumnOrderAttribute(4)] + public string Url { get; set; } + + [ColumnOrderAttribute(5)] + public string ThumbUrl { get; set; } + } +} diff --git a/Win32Client/Program.cs b/Win32Client/Program.cs new file mode 100644 index 0000000..b900942 --- /dev/null +++ b/Win32Client/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Win32Client +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Search()); + } + } +} diff --git a/Win32Client/Properties/AssemblyInfo.cs b/Win32Client/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..11acfb6 --- /dev/null +++ b/Win32Client/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Win32Client")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Win32Client")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("abea9a3e-e9b0-417b-8dd1-76865ff57cd5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Win32Client/Properties/Resources.Designer.cs b/Win32Client/Properties/Resources.Designer.cs new file mode 100644 index 0000000..35da5f8 --- /dev/null +++ b/Win32Client/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Win32Client.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.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() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Win32Client.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [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/Win32Client/Properties/Resources.resx b/Win32Client/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Win32Client/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/Win32Client/Properties/Settings.Designer.cs b/Win32Client/Properties/Settings.Designer.cs new file mode 100644 index 0000000..ac5682c --- /dev/null +++ b/Win32Client/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Win32Client.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.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/Win32Client/Properties/Settings.settings b/Win32Client/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Win32Client/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Win32Client/Search.Designer.cs b/Win32Client/Search.Designer.cs new file mode 100644 index 0000000..0f8f134 --- /dev/null +++ b/Win32Client/Search.Designer.cs @@ -0,0 +1,137 @@ +namespace Win32Client +{ + partial class Search + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.txtSearch = new System.Windows.Forms.TextBox(); + this.listSearchResults = new System.Windows.Forms.ListView(); + this.btnSearch = new System.Windows.Forms.Button(); + this.Thumbs = new System.Windows.Forms.ImageList(this.components); + this.mnuSettings = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.settingsToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuSettings.SuspendLayout(); + this.SuspendLayout(); + // + // txtSearch + // + this.txtSearch.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtSearch.Location = new System.Drawing.Point(13, 27); + this.txtSearch.Name = "txtSearch"; + this.txtSearch.Size = new System.Drawing.Size(386, 20); + this.txtSearch.TabIndex = 0; + // + // listSearchResults + // + this.listSearchResults.Alignment = System.Windows.Forms.ListViewAlignment.Left; + this.listSearchResults.Location = new System.Drawing.Point(13, 62); + this.listSearchResults.MultiSelect = false; + this.listSearchResults.Name = "listSearchResults"; + this.listSearchResults.Size = new System.Drawing.Size(467, 230); + this.listSearchResults.TabIndex = 1; + this.listSearchResults.UseCompatibleStateImageBehavior = false; + this.listSearchResults.View = System.Windows.Forms.View.Tile; + this.listSearchResults.ItemActivate += new System.EventHandler(this.listSearchResults_ItemActivate); + // + // btnSearch + // + this.btnSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnSearch.Location = new System.Drawing.Point(405, 25); + this.btnSearch.Name = "btnSearch"; + this.btnSearch.Size = new System.Drawing.Size(75, 23); + this.btnSearch.TabIndex = 2; + this.btnSearch.Text = "Search"; + this.btnSearch.UseVisualStyleBackColor = true; + this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click); + // + // Thumbs + // + this.Thumbs.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; + this.Thumbs.ImageSize = new System.Drawing.Size(32, 32); + this.Thumbs.TransparentColor = System.Drawing.Color.Transparent; + // + // mnuSettings + // + this.mnuSettings.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem}); + this.mnuSettings.Location = new System.Drawing.Point(0, 0); + this.mnuSettings.Name = "mnuSettings"; + this.mnuSettings.Size = new System.Drawing.Size(492, 24); + this.mnuSettings.TabIndex = 3; + this.mnuSettings.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.settingsToolStripMenuItem1}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "&File"; + // + // settingsToolStripMenuItem1 + // + this.settingsToolStripMenuItem1.Name = "settingsToolStripMenuItem1"; + this.settingsToolStripMenuItem1.Size = new System.Drawing.Size(152, 22); + this.settingsToolStripMenuItem1.Text = "Settings..."; + this.settingsToolStripMenuItem1.Click += new System.EventHandler(this.settingsToolStripMenuItem1_Click); + // + // Search + // + this.AcceptButton = this.btnSearch; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(492, 304); + this.Controls.Add(this.btnSearch); + this.Controls.Add(this.listSearchResults); + this.Controls.Add(this.txtSearch); + this.Controls.Add(this.mnuSettings); + this.MainMenuStrip = this.mnuSettings; + this.Name = "Search"; + this.Text = "Search Youtube"; + this.Load += new System.EventHandler(this.Search_Load); + this.mnuSettings.ResumeLayout(false); + this.mnuSettings.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox txtSearch; + private System.Windows.Forms.ListView listSearchResults; + private System.Windows.Forms.Button btnSearch; + private System.Windows.Forms.ImageList Thumbs; + private System.Windows.Forms.MenuStrip mnuSettings; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem1; + } +} + diff --git a/Win32Client/Search.cs b/Win32Client/Search.cs new file mode 100644 index 0000000..dee1ec3 --- /dev/null +++ b/Win32Client/Search.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Win32Client.Client; +using Win32Client.Helpers; +using Win32Client.Models; + + +namespace Win32Client +{ + public partial class Search : Form + { + public Search() + { + InitializeComponent(); + + listSearchResults.Columns.Add(new ColumnHeader()); + listSearchResults.LargeImageList = Thumbs; + } + + private void btnSearch_Click(object sender, EventArgs e) + { + var client = new YouTubeProxyClient(ClientSettings.GetSettings().BaseUrl); + var results = client.Search(txtSearch.Text); + + ResultsToListView(results); + } + + private void ResultsToListView(List results) + { + listSearchResults.Items.Clear(); + + + foreach (var result in results) + { + var resultItem = new ListViewItem(); + + + resultItem.Text = result.Title; + resultItem.Tag = result; + + resultItem.SubItems.Add(result.Description); + + listSearchResults.Items.Add(resultItem); + } + + DownloadThumbs(); + } + + private async void DownloadThumbs() + { + Thumbs.Images.Clear(); + + var client = new WebClient(); + for (int i = 0; i < listSearchResults.Items.Count; i++) + { + var item = listSearchResults.Items[i]; + var result = (SearchResultModel)item.Tag; + var data = await client.DownloadDataTaskAsync(new Uri(result.ThumbUrl)); + + + this.UIThread(() => + { + var item2 = listSearchResults.Items[i]; + + // Hack Alert! + Thumbs.Images.Add(new Bitmap(new MemoryStream(data))); + item2.ImageIndex = i; + }); + + } + + } + + private void listSearchResults_ItemActivate(object sender, EventArgs e) + { + + var item = (SearchResultModel)listSearchResults.SelectedItems[0].Tag; + + var videoPlayer = new VideoPlayer(item); + videoPlayer.Show(); + } + + + private void Search_Load(object sender, EventArgs e) + { + + } + + private void settingsToolStripMenuItem_Click(object sender, EventArgs e) + { + + } + + private void settingsToolStripMenuItem1_Click(object sender, EventArgs e) + { + new Settings().ShowDialog(); + } + } +} diff --git a/Win32Client/Search.resx b/Win32Client/Search.resx new file mode 100644 index 0000000..19e4b6e --- /dev/null +++ b/Win32Client/Search.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 112, 17 + + \ No newline at end of file diff --git a/Win32Client/Settings.Designer.cs b/Win32Client/Settings.Designer.cs new file mode 100644 index 0000000..9609f95 --- /dev/null +++ b/Win32Client/Settings.Designer.cs @@ -0,0 +1,182 @@ +namespace Win32Client +{ + partial class Settings + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.txtBaseUrl = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.rbRTSP = new System.Windows.Forms.RadioButton(); + this.rbHttp = new System.Windows.Forms.RadioButton(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.encodeOptionsPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.rbHttp); + this.groupBox1.Controls.Add(this.rbRTSP); + this.groupBox1.Location = new System.Drawing.Point(25, 48); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(371, 89); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Streaming Method"; + // + // txtBaseUrl + // + this.txtBaseUrl.Location = new System.Drawing.Point(103, 13); + this.txtBaseUrl.Name = "txtBaseUrl"; + this.txtBaseUrl.Size = new System.Drawing.Size(276, 20); + this.txtBaseUrl.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(22, 16); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(75, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Base Address:"; + // + // rbRTSP + // + this.rbRTSP.AutoSize = true; + this.rbRTSP.Enabled = false; + this.rbRTSP.Location = new System.Drawing.Point(18, 31); + this.rbRTSP.Name = "rbRTSP"; + this.rbRTSP.Size = new System.Drawing.Size(54, 17); + this.rbRTSP.TabIndex = 0; + this.rbRTSP.Text = "RTSP"; + this.rbRTSP.UseVisualStyleBackColor = true; + // + // rbHttp + // + this.rbHttp.AutoSize = true; + this.rbHttp.Checked = true; + this.rbHttp.Location = new System.Drawing.Point(18, 55); + this.rbHttp.Name = "rbHttp"; + this.rbHttp.Size = new System.Drawing.Size(163, 17); + this.rbHttp.TabIndex = 1; + this.rbHttp.TabStop = true; + this.rbHttp.Text = "HTTP Progressive Download"; + this.rbHttp.UseVisualStyleBackColor = true; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.encodeOptionsPanel); + this.groupBox2.Location = new System.Drawing.Point(25, 144); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(371, 133); + this.groupBox2.TabIndex = 3; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Profile"; + // + // encodeOptionsPanel + // + this.encodeOptionsPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.encodeOptionsPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.encodeOptionsPanel.Location = new System.Drawing.Point(3, 16); + this.encodeOptionsPanel.Name = "encodeOptionsPanel"; + this.encodeOptionsPanel.Size = new System.Drawing.Size(365, 114); + this.encodeOptionsPanel.TabIndex = 0; + this.encodeOptionsPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.encodeOptionsPanel_Paint); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(28, 284); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 4; + this.button1.Text = "Defaults"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + this.button2.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button2.Location = new System.Drawing.Point(229, 284); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 5; + this.button2.Text = "Save"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // button3 + // + this.button3.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button3.Location = new System.Drawing.Point(311, 284); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(75, 23); + this.button3.TabIndex = 6; + this.button3.Text = "Cancel"; + this.button3.UseVisualStyleBackColor = true; + // + // Settings + // + this.AcceptButton = this.button2; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button3; + this.ClientSize = new System.Drawing.Size(424, 319); + this.Controls.Add(this.button3); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtBaseUrl); + this.Controls.Add(this.groupBox1); + this.Name = "Settings"; + this.Text = "Settings"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox txtBaseUrl; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.RadioButton rbHttp; + private System.Windows.Forms.RadioButton rbRTSP; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.FlowLayoutPanel encodeOptionsPanel; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; + } +} \ No newline at end of file diff --git a/Win32Client/Settings.cs b/Win32Client/Settings.cs new file mode 100644 index 0000000..614bd47 --- /dev/null +++ b/Win32Client/Settings.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Win32Client +{ + public partial class Settings : Form + { + private string[] profiles = new string[] + { + "video1", + "cinepak", + "h263", + "sorrensonFFMPEG", + "sorrenson", + "mpeg1", + "mpeg4" + }; + + public Settings() + { + InitializeComponent(); + + BuildCodecList(); + + LoadSettings(ClientSettings.GetSettings()); + } + + public Settings(ClientSettings settings) + { + InitializeComponent(); + + BuildCodecList(); + LoadSettings(settings); + } + + private void BuildCodecList() + { + foreach (var codec in profiles) + { + encodeOptionsPanel.Controls.Add(new RadioButton() + { + Text = codec, + + }); + } + } + + private ClientSettings GetSettings() + { + // Get the profile + var profile = encodeOptionsPanel.Controls.Cast().FirstOrDefault(c => c.Checked == true).Text; + + return new ClientSettings + { + BaseUrl = txtBaseUrl.Text, + Profile = profile + }; + } + + private void LoadSettings(ClientSettings settings) + { + txtBaseUrl.Text = settings.BaseUrl; + encodeOptionsPanel.Controls.Cast().FirstOrDefault(c => c.Text == settings.Profile).Checked = true; + + } + + private void encodeOptionsPanel_Paint(object sender, PaintEventArgs e) + { + + } + + private void button2_Click(object sender, EventArgs e) + { + this.GetSettings().SaveSettings(); + } + } +} diff --git a/Win32Client/Settings.resx b/Win32Client/Settings.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Win32Client/Settings.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Win32Client/VideoPlayer.Designer.cs b/Win32Client/VideoPlayer.Designer.cs new file mode 100644 index 0000000..161d7ad --- /dev/null +++ b/Win32Client/VideoPlayer.Designer.cs @@ -0,0 +1,107 @@ +namespace Win32Client +{ + partial class VideoPlayer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VideoPlayer)); + this.axQTControl1 = new AxQTOControlLib.AxQTControl(); + this.lblTitle = new System.Windows.Forms.Label(); + this.lblDescription = new System.Windows.Forms.Label(); + this.encodeProgress = new System.Windows.Forms.ProgressBar(); + ((System.ComponentModel.ISupportInitialize)(this.axQTControl1)).BeginInit(); + this.SuspendLayout(); + // + // axQTControl1 + // + this.axQTControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.axQTControl1.Enabled = true; + this.axQTControl1.Location = new System.Drawing.Point(0, 0); + this.axQTControl1.Name = "axQTControl1"; + this.axQTControl1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("axQTControl1.OcxState"))); + this.axQTControl1.Size = new System.Drawing.Size(352, 240); + this.axQTControl1.TabIndex = 0; + // + // lblTitle + // + this.lblTitle.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblTitle.AutoSize = true; + this.lblTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTitle.Location = new System.Drawing.Point(12, 243); + this.lblTitle.Name = "lblTitle"; + this.lblTitle.Size = new System.Drawing.Size(45, 13); + this.lblTitle.TabIndex = 1; + this.lblTitle.Text = "lblTitle"; + // + // lblDescription + // + this.lblDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblDescription.Location = new System.Drawing.Point(13, 260); + this.lblDescription.Name = "lblDescription"; + this.lblDescription.Size = new System.Drawing.Size(327, 85); + this.lblDescription.TabIndex = 2; + this.lblDescription.Text = "lblDescription"; + // + // encodeProgress + // + this.encodeProgress.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.encodeProgress.Location = new System.Drawing.Point(13, 358); + this.encodeProgress.Name = "encodeProgress"; + this.encodeProgress.Size = new System.Drawing.Size(327, 13); + this.encodeProgress.TabIndex = 3; + // + // VideoPlayer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(352, 381); + this.Controls.Add(this.encodeProgress); + this.Controls.Add(this.lblDescription); + this.Controls.Add(this.lblTitle); + this.Controls.Add(this.axQTControl1); + this.Name = "VideoPlayer"; + this.Text = "VideoPlayer"; + this.Load += new System.EventHandler(this.VideoPlayer_Load); + ((System.ComponentModel.ISupportInitialize)(this.axQTControl1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private AxQTOControlLib.AxQTControl axQTControl1; + private System.Windows.Forms.Label lblTitle; + private System.Windows.Forms.Label lblDescription; + private System.Windows.Forms.ProgressBar encodeProgress; + } +} \ No newline at end of file diff --git a/Win32Client/VideoPlayer.cs b/Win32Client/VideoPlayer.cs new file mode 100644 index 0000000..cdae140 --- /dev/null +++ b/Win32Client/VideoPlayer.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Win32Client.Client; +using Win32Client.Models; + +namespace Win32Client +{ + public partial class VideoPlayer : Form + { + private SearchResultModel item; + private YouTubeProxyClient Client { get; set; } + public ClientSettings Settings = ClientSettings.GetSettings(); + + private Timer encodeCheckTimer; + + public VideoPlayer() + { + InitializeComponent(); + + } + + public VideoPlayer(SearchResultModel item) + { + InitializeComponent(); + this.item = item; + this.Client = new YouTubeProxyClient(ClientSettings.GetSettings().BaseUrl); + + // Start Encoding + this.StartEncode(); + } + + + + private void VideoPlayer_Load(object sender, EventArgs e) + { + this.Text = item.Title; + lblTitle.Text = item.Title; + lblDescription.Text = item.Description; + } + + private void StartEncode() + { + encodeCheckTimer = new Timer(); + encodeCheckTimer.Interval = 1000; + encodeCheckTimer.Tick += Timer_Tick; + encodeCheckTimer.Start(); + } + + private void Timer_Tick(object sender, EventArgs e) + { + var encodeResult = Client.GetVideo(item.VideoId, Settings.Profile).First(); // should only be one + + + switch (encodeResult.Status) + { + case ConversionStatusModel.StatusCodes.Encoding: + encodeProgress.Maximum = 100; + encodeProgress.Value = encodeResult.Progress; + break; + case ConversionStatusModel.StatusCodes.Error: + encodeCheckTimer.Stop(); + encodeProgress.Hide(); + MessageBox.Show("Error Encoding Video. Error: " + encodeResult.Error); + break; + case ConversionStatusModel.StatusCodes.ReadyForDownload: + encodeCheckTimer.Stop(); + encodeProgress.Hide(); + PlayVideo(); + break; + } + } + + private void PlayVideo() + { + axQTControl1.URL = string.Concat(Settings.BaseUrl, "api/Download/mov/", this.item.VideoId); + axQTControl1.Show(); + + } + } +} diff --git a/Win32Client/VideoPlayer.resx b/Win32Client/VideoPlayer.resx new file mode 100644 index 0000000..a3ac2d7 --- /dev/null +++ b/Win32Client/VideoPlayer.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACFTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5BeEhvc3QrU3RhdGUBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAVQAAAAIB + AAAAAQAAAAAAAAAAAAAAAEAAAAAACAAA2BMAANgTAAATAA8AAIATAAAAAAADAAEAAAALAP//AwACAAAA + CAACAAAAAAAIAAIAAAAAAAgAAgAAAAAACw== + + + \ No newline at end of file diff --git a/Win32Client/Win32Client.csproj b/Win32Client/Win32Client.csproj new file mode 100644 index 0000000..f616f65 --- /dev/null +++ b/Win32Client/Win32Client.csproj @@ -0,0 +1,161 @@ + + + + + Debug + AnyCPU + {ABEA9A3E-E9B0-417B-8DD1-76865FF57CD5} + WinExe + Properties + Win32Client + Win32Client + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + ..\bin\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + bin\ClientTest\ + + + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + + + + + + + + + + + + + + Form + + + Search.cs + + + + + Form + + + Settings.cs + + + Form + + + VideoPlayer.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + Search.cs + + + Settings.cs + + + VideoPlayer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + {7B92F833-027D-402B-BFF9-A67697366F4E} + 1 + 0 + 0 + aximp + False + + + {7B92F833-027D-402B-BFF9-A67697366F4E} + 1 + 0 + 0 + tlbimp + False + True + + + {29866AED-1E14-417D-BA0F-1A2BE6F5A19E} + 1 + 0 + 0 + tlbimp + False + True + + + {00020430-0000-0000-C000-000000000046} + 2 + 0 + 0 + primary + False + True + + + + + + \ No newline at end of file diff --git a/Win32Client/packages.config b/Win32Client/packages.config new file mode 100644 index 0000000..810e559 --- /dev/null +++ b/Win32Client/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file