diff --git a/FoxTube.Background/BackgroundProcessor.cs b/FoxTube.Background/BackgroundProcessor.cs index 83ff2c7..7bfe196 100644 --- a/FoxTube.Background/BackgroundProcessor.cs +++ b/FoxTube.Background/BackgroundProcessor.cs @@ -1,171 +1,12 @@ -using Google.Apis.Auth.OAuth2; -using Google.Apis.Oauth2.v2; -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using System.Xml; -using Windows.ApplicationModel.Background; -using Windows.Storage; -using Windows.UI.Notifications; +using Windows.ApplicationModel.Background; namespace FoxTube.Background { public sealed class BackgroundProcessor : IBackgroundTask { - private DateTime lastCheck; - private readonly ApplicationDataContainer settings = ApplicationData.Current.RoamingSettings; - dynamic prefs; - BackgroundTaskDeferral def; - public async void Run(IBackgroundTaskInstance taskInstance) { - try - { - def = taskInstance.GetDeferral(); - if (settings.Values["lastCheck"] == null) - { - settings.Values["lastCheck"] = DateTime.Now.ToString(); - def.Complete(); - return; - } - else - lastCheck = DateTime.Parse(settings.Values["lastCheck"] as string); - - prefs = JsonConvert.DeserializeObject(settings.Values["settings"] as string); - if ((bool)prefs.devNotifications) - CheckAnnouncements(); - if ((bool)prefs.videoNotifications && (bool)prefs.hasAccount) - await CheckAccount(); - } - finally - { - settings.Values["lastCheck"] = DateTime.Now.ToString(); - def.Complete(); - } - } - - async Task CheckAccount() - { - try - { - UserCredential Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( - new ClientSecrets - { - ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com", - ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_" - }, - new[] - { - Oauth2Service.Scope.UserinfoProfile, - Oauth2Service.Scope.UserinfoEmail, - YouTubeService.Scope.YoutubeForceSsl, - YouTubeService.Scope.Youtube, - YouTubeService.Scope.YoutubeUpload, - YouTubeService.Scope.YoutubeReadonly, - YouTubeService.Scope.Youtubepartner - }, - "user", - CancellationToken.None); - - if (Credential == null) - return; - - YouTubeService service = new YouTubeService(new BaseClientService.Initializer - { - HttpClientInitializer = Credential, - ApplicationName = "FoxTube" - }); - - List subscriptions = new List(); - List results = new List(); - - SubscriptionsResource.ListRequest subRequest = service.Subscriptions.List("snippet"); - subRequest.Mine = true; - subRequest.MaxResults = 50; - subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance; - SubscriptionListResponse subResponse; - string nextToken = null; - - do - { - subRequest.PageToken = nextToken; - subResponse = await subRequest.ExecuteAsync(); - foreach (Subscription s in subResponse.Items) - subscriptions.Add(s); - nextToken = subResponse.NextPageToken; - - } while (!string.IsNullOrWhiteSpace(nextToken)); - - foreach (Subscription item in subscriptions) - { - SearchResource.ListRequest request = service.Search.List("snippet"); - request.PublishedAfter = lastCheck; - request.ChannelId = item.Snippet.ResourceId.ChannelId; - request.Type = "video"; - request.MaxResults = 5; - SearchListResponse response = await request.ExecuteAsync(); - - foreach (SearchResult i in response.Items) - { - results.Add(i); - - if (i.Snippet.LiveBroadcastContent == "live") - ToastNotificationManager.CreateToastNotifier().Show( - Notification.GetStreamToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, item.Snippet.Thumbnails.Default__.Url)); - else if (i.Snippet.LiveBroadcastContent == "upcoming") - ToastNotificationManager.CreateToastNotifier().Show( - Notification.GetUpcomingToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, item.Snippet.Thumbnails.Default__.Url)); - else - ToastNotificationManager.CreateToastNotifier().Show( - Notification.GetVideoToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, item.Snippet.Thumbnails.Default__.Url)); - } - } - - results.OrderBy(i => i.Snippet.PublishedAt); - - TileUpdater updater = TileUpdateManager.CreateTileUpdaterForApplication(); - updater.EnableNotificationQueue(true); - updater.Clear(); - for (int i = 0; i < 5 && i < results.Count; i++) - updater.Update(Tiles.GetTileLayout(System.Security.SecurityElement.Escape(results[i].Snippet.Title.ConvertEscapeSymbols()), System.Security.SecurityElement.Escape(results[i].Snippet.ChannelTitle), results[i].Snippet.Thumbnails.Medium.Url.Replace("&", "%26"), subscriptions.Find(x => x.Snippet.ResourceId.ChannelId == results[i].Snippet.ChannelId).Snippet.Thumbnails.Medium.Url)); - } - catch { } - } - - async void CheckAnnouncements() - { - try - { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(await new HttpClient().GetStringAsync("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml")); - XmlElement item = doc["posts"].FirstChild as XmlElement; - - DateTime date = DateTime.Parse(item.GetAttribute("time")); - if (date > lastCheck && date < DateTime.Now) - ToastNotificationManager.CreateToastNotifier().Show( - Notification.GetInternalToast(item["id"].InnerText, - item["header"][(string)prefs.language].InnerText, - item["content"][(string)prefs.language].InnerText, - item["thumbnail"].InnerText, - item["avatar"].InnerText)); - } - catch { } - } - } - - public static class Ext - { - public static string ConvertEscapeSymbols(this string str) - { - return str.Replace(""", "\"").Replace("'", "'").Replace("<", "<").Replace(">", ">").Replace("&", "&").Replace(""", "\"").Replace("'", "'").Replace("<", "<").Replace(">", ">").Replace("&", "&"); } } } diff --git a/FoxTube.Background/FoxTube.Background.csproj b/FoxTube.Background/FoxTube.Background.csproj index 4dbe1ff..3eec541 100644 --- a/FoxTube.Background/FoxTube.Background.csproj +++ b/FoxTube.Background/FoxTube.Background.csproj @@ -108,7 +108,6 @@ - diff --git a/FoxTube.Background/ResourceCreators.cs b/FoxTube.Background/ResourceCreators.cs deleted file mode 100644 index b5fd2a0..0000000 --- a/FoxTube.Background/ResourceCreators.cs +++ /dev/null @@ -1,197 +0,0 @@ -using Google.Apis.YouTube.v3.Data; -using Microsoft.Toolkit.Uwp.Notifications; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using Windows.Data.Xml.Dom; -using Windows.Storage; -using Windows.UI.Notifications; - -namespace FoxTube.Background -{ - public static class Notification - { - private static readonly Dictionary languagePack = LoadPack(); - - private static Dictionary LoadPack() - { - dynamic saved = JsonConvert.DeserializeObject(ApplicationData.Current.RoamingSettings.Values["settings"] as string); - string hl = saved.language; - if (hl == "ru-RU") - return new Dictionary() - { - { "addLater", "Посмотреть позже" }, - { "changelog", "Список изменений" }, - { "changelogHeader", "Что нового в версии" }, - { "videoContent", "загрузил новое видео" }, - { "live", "ПРЯМОЙ ЭФИР" }, - { "upcoming", "Запланирован" }, - { "liveContent", "начал прямой эфир" }, - { "upcomingContent", "запланировал прямой эфир" }, - { "goChannel", "Открыть канал" } - }; - else - return new Dictionary() - { - { "addLater", "Add to Watch later" }, - { "changelog", "Changelog" }, - { "changelogHeader", "What's new in version" }, - { "videoContent", "uploaded a new video" }, - { "live", "LIVE" }, - { "upcoming", "Upcoming" }, - { "liveContent", "started live broadcast" }, - { "upcomingContent", "planned live broadcast" }, - { "goChannel", "Go to channel" } - }; - } - - public static ToastNotification GetChangelogToast(string version) - { - XmlDocument template = new XmlDocument(); - - template.LoadXml($@" - - - - - {languagePack["changelog"]} - {languagePack["changelogHeader"]} {version} - - - "); - - return new ToastNotification(template); - } - - public static ToastNotification GetVideoToast(string id, string channelId, string title, string channel, string thumbnail, DateTimeOffset timeStamp, string avatar) - { - XmlDocument template = new XmlDocument(); - string ts = $"{timeStamp.Year}-{timeStamp.Month:00}-{timeStamp.Day:00}T{timeStamp.Hour:00}:{timeStamp.Minute:00}:{timeStamp.Second:00}Z"; - template.LoadXml($@" - - - - - {System.Security.SecurityElement.Escape(title)} - {System.Security.SecurityElement.Escape(channel)} {languagePack["videoContent"]} - - - - - - - - "); - - return new ToastNotification(template); - } - public static ToastNotification GetStreamToast(string id, string channelId, string title, string channel, string thumbnail, DateTimeOffset timeStamp, string avatar) - { - XmlDocument template = new XmlDocument(); - string ts = $"{timeStamp.Year}-{timeStamp.Month:00}-{timeStamp.Day:00}T{timeStamp.Hour:00}:{timeStamp.Minute:00}:{timeStamp.Second:00}Z"; - template.LoadXml($@" - - - - - 🔴 [{languagePack["live"]}] {System.Security.SecurityElement.Escape(title)} - {System.Security.SecurityElement.Escape(channel)} {languagePack["liveContent"]} - - - - - - - "); - - return new ToastNotification(template); - } - public static ToastNotification GetUpcomingToast(string id, string channelId, string title, string channel, string thumbnail, DateTimeOffset timeStamp, string avatar) - { - XmlDocument template = new XmlDocument(); - string ts = $"{timeStamp.Year}-{timeStamp.Month:00}-{timeStamp.Day:00}T{timeStamp.Hour:00}:{timeStamp.Minute:00}:{timeStamp.Second:00}Z"; - template.LoadXml($@" - - - - - 🔴 [{languagePack["upcoming"]}] {System.Security.SecurityElement.Escape(title)} - {System.Security.SecurityElement.Escape(channel)} {languagePack["upcomingContent"]} - - - - - - - "); - - return new ToastNotification(template); - } - - public static ToastNotification GetInternalToast(string id, string header, string content, string thumbnail, string avatar) - { - XmlDocument template = new XmlDocument(); - - template.LoadXml($@" - - - - - {header} - {content} - - - "); - - return new ToastNotification(template); - } - } - - public static class Tiles - { - public static TileNotification GetTileLayout(string title, string channel, string thumbnail, string avatar) - { - XmlDocument doc = new XmlDocument(); - - doc.LoadXml($@" - - - - - - {channel} - {title} - - - - - - - - - - {channel} - {title} - - - - - - - - - - - - {channel} - {title} - - - - - "); - - return new TileNotification(doc); - } - } -} diff --git a/FoxTube/App.xaml.cs b/FoxTube/App.xaml.cs index 0d49758..c0f2ed0 100644 --- a/FoxTube/App.xaml.cs +++ b/FoxTube/App.xaml.cs @@ -1,8 +1,6 @@ -using FoxTube.Classes; -using Microsoft.AppCenter.Analytics; -using System.Collections.Generic; +using FoxTube.Pages; +using System.Diagnostics; using Windows.ApplicationModel.Activation; -using Windows.Globalization; using Windows.UI.Notifications; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -13,32 +11,10 @@ namespace FoxTube { public App() { - SettingsStorage.LoadData(); - - switch (SettingsStorage.Theme) - { - case 0: - RequestedTheme = ApplicationTheme.Light; - break; - case 1: - RequestedTheme = ApplicationTheme.Dark; - break; - } - ApplicationLanguages.PrimaryLanguageOverride = SettingsStorage.Language; - InitializeComponent(); - Suspending += (s, e) => Processes.SuspendApp(); - UnhandledException += (s, e) => Analytics.TrackEvent("The app crashed", new Dictionary() - { - { "Exception", e.Exception.GetType().ToString() }, - { "Details", e.Message }, - { "StackTrace", e.Exception.StackTrace } - }); - - Processes.InitializeApp(); } - protected override void OnLaunched(LaunchActivatedEventArgs e) + /*protected override void OnLaunched(LaunchActivatedEventArgs e) { if (!(Window.Current.Content is Frame)) Window.Current.Content = new Frame(); @@ -50,19 +26,11 @@ namespace FoxTube Window.Current.Activate(); } - } + }*/ protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args) { - var deferral = args.TaskInstance.GetDeferral(); base.OnBackgroundActivated(args); - - if (args.TaskInstance.Task.Name == "FoxtubeToastBackground" || !(args.TaskInstance.TriggerDetails is ToastNotificationActionTriggerDetail details)) - return; - - Processes.ProcessToast(details.Argument); - - deferral.Complete(); } protected override void OnActivated(IActivatedEventArgs e) @@ -70,26 +38,18 @@ namespace FoxTube base.OnActivated(e); //TODO: Check this shit - /*if (!(Window.Current.Content is Frame rootFrame)) + if (!(Window.Current.Content is Frame rootFrame)) { rootFrame = new Frame(); - rootFrame.NavigationFailed += OnNavigationFailed; - Window.Current.Content = rootFrame; } if (rootFrame.Content == null) rootFrame.Navigate(typeof(MainPage)); - Window.Current.Activate();*/ + Window.Current.Activate(); - if (e.Kind != ActivationKind.ToastNotification) - return; - - if (SecretsVault.IsAuthorized) - Processes.ProcessToast((e as ToastNotificationActivatedEventArgs).Argument); - else - SecretsVault.AuthorizationStateChanged += (arg) => Processes.ProcessToast((e as ToastNotificationActivatedEventArgs).Argument); + Debug.WriteLine("Hello, World"); } } } diff --git a/FoxTube/Assets/FoxGame.png b/FoxTube/Assets/FoxGame.png deleted file mode 100644 index bccd146..0000000 Binary files a/FoxTube/Assets/FoxGame.png and /dev/null differ diff --git a/FoxTube/Assets/LockScreenLogo.scale-200.png b/FoxTube/Assets/LockScreenLogo.scale-200.png deleted file mode 100644 index 735f57a..0000000 Binary files a/FoxTube/Assets/LockScreenLogo.scale-200.png and /dev/null differ diff --git a/FoxTube/Assets/StoreLogo.backup.png b/FoxTube/Assets/StoreLogo.backup.png deleted file mode 100644 index 7385b56..0000000 Binary files a/FoxTube/Assets/StoreLogo.backup.png and /dev/null differ diff --git a/FoxTube/Classes/AdaptiveCommandBar.cs b/FoxTube/Classes/AdaptiveCommandBar.cs deleted file mode 100644 index 3af6a2d..0000000 --- a/FoxTube/Classes/AdaptiveCommandBar.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Windows.UI.Xaml.Controls; - -namespace FoxTube.Classes -{ - class AdaptiveCommandBar : CommandBar - { - public AdaptiveCommandBar() => - ClosedDisplayMode = SettingsStorage.AppBarClosedMode; - } -} diff --git a/FoxTube/Classes/DownloadAgent.cs b/FoxTube/Classes/DownloadAgent.cs deleted file mode 100644 index 1cfffdf..0000000 --- a/FoxTube/Classes/DownloadAgent.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using Windows.Storage; -using Newtonsoft.Json; -using YoutubeExplode.Models.MediaStreams; -using FoxTube.Controls; -using FoxTube.Pages; -using Microsoft.AppCenter.Analytics; -using YoutubeExplode.Models; - -namespace FoxTube -{ - public static class DownloadAgent - { - public static List Items { get; set; } = new List(); - static readonly ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; - public static Downloads Page { get; set; } - public static StorageFolder Downloads { get; set; } - - public static async void Initialize() - { - Items.Clear(); - try - { - Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists); - List containers = JsonConvert.DeserializeObject>((string)settings.Values[$"downloads"]); - containers.ForEach(i => Items.Add(new DownloadItem(i))); - } - catch (Exception e) - { - settings.Values["downloads"] = JsonConvert.SerializeObject(new List()); - Analytics.TrackEvent("Failed to load downloads history", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "StackTrace", e.StackTrace } - }); - } - } - - public static void Add((MediaStreamInfo info, Video meta, string qualty) e) => - Items.Insert(0, new DownloadItem(e.info, e.meta, e.qualty)); - - public static void Remove(DownloadItem item) - { - Page?.Remove(item); - Items.Remove(item); - } - - - public static void Cancel(string id) - { - DownloadItem item = Items.Find(i => i.Container.Id == id); - if (item != null) - item.Cancel(); - } - - public static void QuitPrompt() - { - foreach (DownloadItem i in Items.FindAll(i => !i.Container.IsDownloaded)) - { - i.Cancel(); - Items.Remove(i); - } - - List containers = new List(); - Items.ForEach(i => containers.Add(i.Container)); - - string data = JsonConvert.SerializeObject(containers); - - settings.Values[$"downloads"] = data; - } - } -} diff --git a/FoxTube/Classes/Extensions.cs b/FoxTube/Classes/Extensions.cs deleted file mode 100644 index 7efc0f9..0000000 --- a/FoxTube/Classes/Extensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Google.Apis.YouTube.v3.Data; -using System; -using System.Threading.Tasks; - -namespace FoxTube.Classes -{ - public delegate void SubscriptionsChangedEventHandler(string action, Subscription subscription); - public delegate void AuthorizationChangedEventHandler(bool? isAuthorized); - public delegate void MinimodeChangedEventHandler(bool isOn); - public delegate void SimpleEventHandler(); - public delegate void PlaylistItemChangedEventHandler(string id); - public delegate void NavigationEventHanlder(Type sourcePageType, object parameter); - - public static class Extensions - { - public static bool Belongs(this double num, double x1, double x2) - { - return num > x1 && num < x2; - } - } - - public interface INavigationPage - { - object Parameter { get; set; } - } - - public interface ICard - { - Task Initialize(); - void ItemClicked(); - } - - public enum PlayerDisplayState { Normal, Minimized, Compact } -} diff --git a/FoxTube/Classes/HistorySet.cs b/FoxTube/Classes/HistorySet.cs deleted file mode 100644 index 7e95ccc..0000000 --- a/FoxTube/Classes/HistorySet.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using Windows.Storage; - -namespace FoxTube -{ - public class HistoryItem - { - public string Id { get; set; } - public TimeSpan LeftOn { get; set; } = TimeSpan.FromSeconds(0); - } - - public static class HistorySet - { - public static List Items { get; set; } = new List(); - - public static void Update(HistoryItem item) - { - if (!SecretsVault.IsAuthorized) - return; - - Items.RemoveAll(i => i.Id == item.Id); - - Items.Insert(0, item); - if (Items.Count > 200) - Items.RemoveRange(200, Items.Count - 200); - Save(); - } - - public static void Delete(HistoryItem item) - { - if (!SecretsVault.IsAuthorized) - return; - - Items.Remove(item); - Save(); - } - - public static void Clear() - { - if (!SecretsVault.IsAuthorized) - return; - - Items.Clear(); - Save(); - } - - public static void Save() - { - List[] parts = new List[4] - { - new List(), new List(), - new List(), new List() - }; - - foreach(HistoryItem i in Items) - if (parts[0].Count < 50) - parts[0].Add(i); - else - { - if (parts[1].Count < 50) - parts[1].Add(i); - else - { - if (parts[2].Count < 50) - parts[2].Add(i); - else - parts[3].Add(i); - } - } - - for(int k = 0; k < parts.Length; k++) - ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}-level{k}"] = JsonConvert.SerializeObject(parts[k]); - } - - public static void Load() - { - try - { - for (int k = 0; k < 4; k++) - Items.AddRange(JsonConvert.DeserializeObject>(ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}-level{k}"] as string)); - } - catch { } - } - } -} diff --git a/FoxTube/Classes/InboxItem.cs b/FoxTube/Classes/InboxItem.cs deleted file mode 100644 index f2def2f..0000000 --- a/FoxTube/Classes/InboxItem.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using Windows.ApplicationModel.Resources; - -namespace FoxTube.Classes -{ - public enum InboxItemType { Default, PatchNote } - - public class InboxItem - { - public InboxItemType Type { get; set; } = InboxItemType.Default; - public DateTime TimeStamp { get; set; } - public string TimeStampString => Type == InboxItemType.PatchNote ? TimeStamp.ToShortDateString() : TimeStamp.ToString(); - - public string Subject { get; set; } - public string Content { get; set; } - public string Id { get; set; } - - private ResourceLoader resources = ResourceLoader.GetForCurrentView("Inbox"); - - public string Icon => Type == InboxItemType.PatchNote ? "\xE728" : "\xE119"; - public string Subtitle => Type == InboxItemType.PatchNote ? resources.GetString("changelog") : resources.GetString("dev"); - - public string Title => Type == InboxItemType.PatchNote ? $"{resources.GetString("whatsnew")}{Id}" : Subject; - - public InboxItem(string version, string content, DateTime timeStamp) - { - Type = InboxItemType.PatchNote; - Content = content; - TimeStamp = timeStamp; - Id = version; - } - - public InboxItem(string title, string content, DateTime timeStamp, string id, string header) - { - Type = InboxItemType.Default; - Content = header + "\n\n" + content; - Subject = title; - TimeStamp = timeStamp; - Id = id; - } - } -} diff --git a/FoxTube/Classes/ManifestGenerator.cs b/FoxTube/Classes/ManifestGenerator.cs deleted file mode 100644 index c187b16..0000000 --- a/FoxTube/Classes/ManifestGenerator.cs +++ /dev/null @@ -1,304 +0,0 @@ -using AngleSharp.Html.Dom; -using AngleSharp.Html.Parser; -using Google.Apis.YouTube.v3.Data; -using Microsoft.AppCenter.Analytics; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Xml; -using Windows.ApplicationModel.Resources; -using Windows.Storage; -using YoutubeExplode.Models.MediaStreams; - -namespace FoxTube.Classes -{ - public static class ManifestGenerator - { - static readonly StorageFolder roaming = ApplicationData.Current.RoamingFolder; - public static async Task GetManifest(Video meta, VideoStreamInfo requestedQuality, MediaStreamInfoSet list) - { - StorageFile manifest; - try { manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.ReplaceExisting); } - catch { manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.GenerateUniqueName); } - - try - { - XmlDocument doc = new XmlDocument(); - - XmlElement mpd = doc.CreateElement("MPD"); - mpd.SetAttribute("mediaPresentationDuration", meta.ContentDetails.Duration); - mpd.SetAttribute("minBufferTime", "PT2S"); - mpd.SetAttribute("profiles", "urn:mpeg:dash:profile:isoff-on-demand:2011"); - mpd.SetAttribute("type", "static"); - - XmlElement period = doc.CreateElement("Period"); - - XmlElement videoSet = doc.CreateElement("AdaptationSet"); - XmlElement videoMeta = doc.CreateElement("ContentComponent"); - videoMeta.SetAttribute("contentType", "video"); - videoMeta.SetAttribute("id", "1"); - videoSet.AppendChild(videoMeta); - - StreamInfo streamInfo = await GetInfoAsync(meta, requestedQuality); - - foreach (var i in streamInfo.Video) - videoSet.AppendChild(GetVideoPresentation(doc, i)); - - XmlElement audioSet = doc.CreateElement("AdaptationSet"); - XmlElement audioMeta = doc.CreateElement("ContentComponent"); - audioMeta.SetAttribute("contentType", "audio"); - audioMeta.SetAttribute("id", "2"); - audioSet.AppendChild(audioMeta); - - foreach (var i in streamInfo.Audio) - audioSet.AppendChild(GetAudioPresentation(doc, i)); - - doc.AppendChild(mpd); - mpd.AppendChild(period); - period.AppendChild(videoSet); - period.AppendChild(audioSet); - - doc.Save(await manifest.OpenStreamForWriteAsync()); - - return $"ms-appdata:///roaming/{manifest.Name}".ToUri(); - } - catch (Exception e) - { - Analytics.TrackEvent("Failed to generate manifest", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "Video ID", meta.Id }, - { "Requested quality", requestedQuality.VideoQualityLabel }, - { "StackTrace", e.StackTrace } - }); - return null; - } - } - - static XmlElement GetVideoPresentation(XmlDocument doc, StreamInfo.VideoInfo info) - { - XmlElement representation = doc.CreateElement("Representation"); - representation.SetAttribute("bandwidth", GetBandwidth(info.Label)); - representation.SetAttribute("id", info.Itag); - representation.SetAttribute("mimeType", info.MimeType); - representation.SetAttribute("codecs", info.Codecs); - representation.SetAttribute("fps", info.Fps); - representation.SetAttribute("height", info.Height); - representation.SetAttribute("width", info.Width); - - XmlElement baseUrl = doc.CreateElement("BaseURL"); - baseUrl.InnerText = info.Url; - representation.AppendChild(baseUrl); - - XmlElement segmentBase = doc.CreateElement("SegmentBase"); - segmentBase.SetAttribute("indexRange", info.IndexRange); - representation.AppendChild(segmentBase); - - XmlElement initialization = doc.CreateElement("Initialization"); - initialization.SetAttribute("range", info.InitRange); - segmentBase.AppendChild(initialization); - - return representation; - } - - static XmlElement GetAudioPresentation(XmlDocument doc, StreamInfo.AudioInfo info) - { - XmlElement audio = doc.CreateElement("Representation"); - audio.SetAttribute("bandwidth", "200000"); - audio.SetAttribute("id", info.Itag); - audio.SetAttribute("sampleRate", info.SampleRate); - audio.SetAttribute("numChannels", info.ChannelsCount); - audio.SetAttribute("codecs", info.Codecs); - audio.SetAttribute("mimeType", info.MimeType); - - XmlElement audioUrl = doc.CreateElement("BaseURL"); - audioUrl.InnerText = info.Url; - audio.AppendChild(audioUrl); - - XmlElement audioSegmentBase = doc.CreateElement("SegmentBase"); - audioSegmentBase.SetAttribute("indexRange", info.IndexRange); - audio.AppendChild(audioSegmentBase); - - XmlElement audioInit = doc.CreateElement("Initialization"); - audioInit.SetAttribute("range", info.InitRange); - audioSegmentBase.AppendChild(audioInit); - - return audio; - } - - static async Task GetInfoAsync(Video info, VideoStreamInfo requestedQuality) - { - try - { - StreamInfo si = new StreamInfo(); - HttpClient http = new HttpClient(); - - string response = await http.GetStringAsync($"https://youtube.com/watch?v={info.Id}&disable_polymer=true&bpctr=9999999999&hl=en"); - IHtmlDocument videoEmbedPageHtml = new HtmlParser().ParseDocument(response); - - string playerConfigRaw = Regex.Match(videoEmbedPageHtml.Source.Text, - @"ytplayer\.config = (?\{[^\{\}]*(((?\{)[^\{\}]*)+((?\})[^\{\}]*)+)*(?(Open)(?!))\})") - .Groups["Json"].Value; - JToken playerConfigJson = JToken.Parse(playerConfigRaw); - - var playerResponseRaw = playerConfigJson.SelectToken("args.player_response").Value(); - JToken playerResponseJson = JToken.Parse(playerResponseRaw); - string errorReason = playerResponseJson.SelectToken("playabilityStatus.reason")?.Value(); - if (!string.IsNullOrWhiteSpace(errorReason)) - throw new InvalidDataException($"Video [{info.Id}] is unplayable. Reason: {errorReason}"); - - List> adaptiveStreamInfosUrl = playerConfigJson.SelectToken("args.adaptive_fmts")?.Value().Split(',').Select(SplitQuery).ToList(); - List> video = - requestedQuality == null ? - adaptiveStreamInfosUrl.FindAll(i => i.ContainsKey("quality_label")) : - adaptiveStreamInfosUrl.FindAll(i => i.ContainsValue(requestedQuality.VideoQualityLabel)); - List> audio = adaptiveStreamInfosUrl.FindAll(i => i.ContainsKey("audio_sample_rate")); - - foreach (var i in video) - si.Video.Add(new StreamInfo.VideoInfo - { - IndexRange = i["index"], - Url = i["url"], - Itag = i["itag"], - Fps = i["fps"], - Height = i["size"].Split('x')[1], - Width = i["size"].Split('x')[0], - Codecs = i["type"].Split('"')[1], - MimeType = i["type"].Split(';')[0], - Label = i["quality_label"] - }); - - foreach (var i in audio) - si.Audio.Add(new StreamInfo.AudioInfo - { - ChannelsCount = i["audio_channels"], - IndexRange = i["index"], - SampleRate = i["audio_sample_rate"], - Codecs = i["type"].Split('"')[1], - MimeType = i["type"].Split(';')[0], - Url = i["url"], - Itag = i["itag"] - }); - - return si; - } - catch - { - return new StreamInfo(); - } - } - - static Dictionary SplitQuery(string query) - { - Dictionary dic = new Dictionary(StringComparer.OrdinalIgnoreCase); - string[] paramsEncoded = query.TrimStart('?').Split("&"); - foreach (string paramEncoded in paramsEncoded) - { - string param = WebUtility.UrlDecode(paramEncoded); - - // Look for the equals sign - int equalsPos = param.IndexOf('='); - if (equalsPos <= 0) - continue; - - // Get the key and value - string key = param.Substring(0, equalsPos); - string value = equalsPos < param.Length - ? param.Substring(equalsPos + 1) - : string.Empty; - - // Add to dictionary - dic[key] = value; - } - - return dic; - } - - static string GetBandwidth(string quality) - { - string parsed = quality.Split('p')[0]; - switch (quality) - { - case "4320": - return $"16763040‬"; - case "3072": - return $"11920384"; - case "2880": - return $"11175360"; - case "2160": - return $"8381520"; - case "1440": - return $"5587680‬"; - case "1080": - return $"4190760"; - case "720": - return $"2073921"; - case "480": - return $"869460"; - case "360": - return $"686521"; - case "240": - return $"264835"; - case "144": - default: - return $"100000"; - } - } - - public static async Task> ResolveLiveSteream(string url) - { - List list = new List(); - string playlistRaw = await new HttpClient().GetStringAsync(url); - - List streamsRaw = playlistRaw.Split("#EXT-X-STREAM-INF:").ToList(); - streamsRaw.RemoveAt(0); - List> streams = new List>(); - foreach (string i in streamsRaw) - { - Dictionary item = new Dictionary(); - string[] par = i.Split('\n'); - item.Add("URL", par[1]); - par = par[0].Split(','); - foreach (string k in par) - { - string[] pair = k.Split('='); - if (pair.Length < 2) - continue; - item[pair[0]] = pair[1]; - } - streams.Add(item); - } - - foreach (var i in streams) - { - StreamQuality item = new StreamQuality(); - item.Resolution = $"{i["RESOLUTION"].Split('x')[1]}p"; - item.Url = i["URL"].ToUri(); - list.Add(item); - } - - list.Add(new StreamQuality - { - Resolution = ResourceLoader.GetForCurrentView("VideoPage").GetString("/VideoPage/auto"), - Url = url.ToUri() - }); - list.Reverse(); - - return list; - } - - public static async void ClearRoaming() - { - IReadOnlyList items = await roaming.GetFilesAsync(); - foreach (StorageFile f in items) - await f.DeleteAsync(StorageDeleteOption.PermanentDelete); - } - } -} diff --git a/FoxTube/Classes/Methods.cs b/FoxTube/Classes/Methods.cs deleted file mode 100644 index ca0190e..0000000 --- a/FoxTube/Classes/Methods.cs +++ /dev/null @@ -1,319 +0,0 @@ -using FoxTube.Classes; -using FoxTube.Controls.VideoPage; -using Google.Apis.YouTube.v3.Data; -using Microsoft.AppCenter.Analytics; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Mail; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Xml; -using Windows.ApplicationModel.DataTransfer; -using Windows.ApplicationModel.Resources; -using Windows.Storage.Streams; -using Windows.System; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Documents; -using YoutubeExplode; -using YoutubeExplode.Models.MediaStreams; - -namespace FoxTube -{ - public delegate void Event(); - - public delegate void ObjectEventHandler(object sender = null, params object[] args); - - public static class Methods - { - private static readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods"); - - public static Comments CommentsPage { get; set; } - public static MainPage MainPage => (Window.Current.Content as Frame).Content as MainPage; - - public static async Task AddItemToWL(string id) - { - try - { - SecretsVault.RefreshToken(); - - PlaylistItem item = new PlaylistItem - { - Snippet = new PlaylistItemSnippet - { - ResourceId = new ResourceId - { - Kind = "youtube#video", - VideoId = id - }, - PlaylistId = "WL" - } - }; - - await SecretsVault.Service.PlaylistItems.Insert(item, "snippet").ExecuteAsync(); - return true; - } - catch (Exception e) - { - Analytics.TrackEvent("Failed to add video to WL", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "Video ID", id }, - { "StackTrace", e.StackTrace } - }); - - return false; - } - } - - public static Uri ToUri(this string url) - { - try { return string.IsNullOrWhiteSpace(url) ? null : new Uri(url); } - catch { return null; } - } - - public static string GuardFromNull(string str) => - str ?? string.Empty; - - public static void SendMail(string content) - { - MailMessage msg = new MailMessage(); - msg.To.Add("michael.xfox@outlook.com"); - msg.From = new MailAddress(SecretsVault.EmailCredential.UserName); - msg.Subject = "[Automatic message] FoxTube service message"; - msg.Body = content; - - SmtpClient client = new SmtpClient("smtp.gmail.com", 587); - client.EnableSsl = true; - client.Credentials = SecretsVault.EmailCredential; - client.Send(msg); - } - - public static List ToReversedList(this Array array) - { - List list = new List(); - foreach (object i in array) - list.Add(i); - list.Reverse(); - return list; - } - - public static void ForEach(this IEnumerable array, Action action) => - array.ToList().ForEach(action); - - public static T Find(this IEnumerable array, Predicate match) => - array.ToList().Find(match); - - public static List FindAll(this IEnumerable array, Predicate match) => - array.ToList().FindAll(match); - - public static string ReplaceInvalidChars(this string str, char newValue) - { - foreach (char i in Path.GetInvalidFileNameChars()) - str = str.Replace(i, newValue); - return str; - } - - [Obsolete("Use *YoutubeExplode.Models.Video instead*")] - public static TimeSpan GetDuration(this string str) - { - try - { - return XmlConvert.ToTimeSpan(str); - } - catch (FormatException) - { - TimeSpan time = XmlConvert.ToTimeSpan("PT" + str.Split('T')[1]); - TimeSpan date = TimeSpan.FromDays(int.Parse(str.Split('W')[0].Remove('P')) * 7); - date.Add(time); - - return date; - } - catch (Exception e) - { - Analytics.TrackEvent("Failed to parse duration", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "StackTrace", e.StackTrace } - }); - return TimeSpan.FromMilliseconds(0); - } - } - - public static string GetAgo(DateTime dateTime) - { - TimeSpan span = DateTime.Now - dateTime; - - if (span.TotalMinutes < 1) - return resources.GetString("/Methods/now"); - else if (Math.Round(span.TotalMinutes) == 1) - return resources.GetString("/Methods/oneMinute"); - else if (span.TotalMinutes < 60) - return Math.Round(span.TotalMinutes) + " " + resources.GetString("/Methods/minutes"); - else if (Math.Round(span.TotalHours) == 1) - return resources.GetString("/Methods/oneHr"); - else if (span.TotalHours < 24) - return Math.Round(span.TotalHours) + " " + resources.GetString("/Methods/hrs"); - else if (Math.Round(span.TotalDays) == 1) - return resources.GetString("/Methods/oneDay"); - else if (span.TotalDays < 7) - return Math.Round(span.TotalDays) + " " + resources.GetString("/Methods/days"); - else if (Math.Round(span.TotalDays) == 7) - return resources.GetString("/Methods/oneWeek"); - else if (span.TotalDays < 30) - return Math.Round(span.TotalDays / 7) + " " + resources.GetString("/Methods/weeks"); - else if (Math.Round(span.TotalDays) == 30) - return resources.GetString("/Methods/oneMonth"); - else if (Math.Round(span.TotalDays) < 365) - return Math.Round(span.TotalDays / 30) + " " + resources.GetString("/Methods/months"); - else if (Math.Round(span.TotalDays / 365) == 365) - return resources.GetString("/Methods/oneYear"); - else - return Math.Round(span.TotalDays / 365) + " " + resources.GetString("/Methods/years"); - } - - public static void FormatText(this TextBlock block, string text) - { - block.Inlines.Clear(); - Regex filter = new Regex(@"\b((?:https?://|www\.)\S+)|(\S+@\S+)\b", RegexOptions.IgnoreCase); - Regex link = new Regex(@"\b(?:https?://|www\.)\S+\b", RegexOptions.IgnoreCase); - Regex mail = new Regex(@"\b\S+@\S+\b", RegexOptions.IgnoreCase); - - foreach (string item in filter.Split(text)) - { - if (link.IsMatch(item)) - { - string str = item; - if (!str.Contains("http")) - str = str.Insert(0, "http://"); - - Hyperlink hl = new Hyperlink(); - hl.Click += (s, arg) => ProcessLink(str); - hl.Inlines.Add(new Run { Text = item }); - block.Inlines.Add(hl); - } - else if (mail.IsMatch(item)) - { - Hyperlink hl = new Hyperlink { NavigateUri = $"mailto:{item}".ToUri() }; - hl.Inlines.Add(new Run { Text = item }); - block.Inlines.Add(hl); - } - else - block.Inlines.Add(new Run { Text = item }); - } - } - - public static string GetVideoQualityLabel(this VideoQuality quality) - { - switch (quality) - { - case VideoQuality.High1080: - return "1080p"; - case VideoQuality.High1440: - return "1440p"; - case VideoQuality.High2160: - return "2160p"; - case VideoQuality.High2880: - return "2880p"; - case VideoQuality.High3072: - return "3072p"; - case VideoQuality.High4320: - return "4320p"; - case VideoQuality.High720: - return "720p"; - case VideoQuality.Low144: - return "144p"; - case VideoQuality.Low240: - return "240p"; - case VideoQuality.Medium360: - return "360p"; - case VideoQuality.Medium480: - return "480p"; - default: - return "Unknown"; - } - } - - public async static void ProcessLink(string url) - { - try - { - string type; - - if (YoutubeClient.TryParseChannelId(url, out string output)) - { - type = "channel"; - goto LinkFound; - } - else if (YoutubeClient.TryParsePlaylistId(url, out output)) - { - type = "playlist"; - goto LinkFound; - } - else if (YoutubeClient.TryParseUsername(url, out output)) - { - type = "user"; - goto LinkFound; - } - else if (YoutubeClient.TryParseVideoId(url, out output)) - { - type = "video"; - goto LinkFound; - } - - await Launcher.LaunchUriAsync(new Uri(url)); - return; - - LinkFound: - switch (type) - { - case "channel": - Navigation.GoToChannel(output); - break; - case "video": - Navigation.GoToVideo(output); - break; - case "playlist": - Navigation.GoToPlaylist(output); - break; - case "user": - Navigation.GoToChannel(await new YoutubeClient().GetChannelIdAsync(output)); - break; - } - } - catch { } - } - - public static void Share(DataRequestedEventArgs args, string thumbnail, string title, string url, string type) - { - DataRequest request = args.Request; - - request.Data.Properties.Title = title; - request.Data.Properties.Description = $"{resources.GetString("/Methods/sharing")} {type}"; - - request.Data.SetText(title + "\n" + "#YouTube #FoxTube #SharedWithFoxTube"); - request.Data.SetWebLink(url.ToUri()); - - request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromUri(thumbnail.ToUri()); - request.Data.SetBitmap(RandomAccessStreamReference.CreateFromUri(thumbnail.ToUri())); - } - - public static async Task GetHistory() - { - SecretsVault.RefreshToken(); - - return await new YoutubeClient(SecretsVault.HttpClient).GetPlaylistAsync("HL"); - } - - public static async Task GetLater() - { - SecretsVault.RefreshToken(); - - return await new YoutubeClient(SecretsVault.HttpClient).GetPlaylistAsync("WL"); - } - } -} diff --git a/FoxTube/Classes/Navigation.cs b/FoxTube/Classes/Navigation.cs deleted file mode 100644 index 0c3c2b6..0000000 --- a/FoxTube/Classes/Navigation.cs +++ /dev/null @@ -1,36 +0,0 @@ -using FoxTube.Pages; -using Google.Apis.YouTube.v3.Data; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; - -namespace FoxTube.Classes -{ - public static class Navigation - { - public static MainFrame Frame => ((Window.Current.Content as Frame).Content as MainPage).Content; - - public static void GoToSearch(SearchParameters args) => - Frame.NavigateTo(typeof(Search), new object[] { args, Frame.Frame }); - - public static void GoToChannel(string id) => - Frame.NavigateTo(typeof(ChannelPage), id); - - public static void GoToHome() => - Frame.NavigateTo(typeof(Home)); - - public static void GoToVideo(string id, string playlistId = null, bool incognito = false) => - Frame.OpenVideo(id, playlistId, incognito); - - public static void GoToDeveloper(string id) => - Frame.NavigateTo(typeof(Settings), id); - - public static void GoToPlaylist(string id) => - Frame.NavigateTo(typeof(PlaylistPage), id); - - public static void GoToHistory() => - Frame.NavigateTo(typeof(History)); - - public static void GoToDownloads() => - Frame.NavigateTo(typeof(Downloads)); - } -} diff --git a/FoxTube/Classes/Processes.cs b/FoxTube/Classes/Processes.cs deleted file mode 100644 index 4b9475b..0000000 --- a/FoxTube/Classes/Processes.cs +++ /dev/null @@ -1,299 +0,0 @@ -using Microsoft.AppCenter; -using Microsoft.AppCenter.Analytics; -using Microsoft.Services.Store.Engagement; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Xml; -using Windows.ApplicationModel; -using Windows.ApplicationModel.Background; -using Windows.ApplicationModel.DataTransfer; -using Windows.ApplicationModel.Resources; -using Windows.Storage; -using Windows.System; -using Windows.System.Power; -using Windows.UI.Notifications; -using Windows.UI.Popups; -using Windows.UI.Xaml; -using Windows.UI.Core; - -namespace FoxTube.Classes -{ - public static class Processes - { - static Stopwatch sw = new Stopwatch(); - public static async void InitializeApp() => await CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(CoreDispatcherPriority.High, () => - { - CheckVersion(); - - RegisterToastTask(); - ActivateBackgoundTask(); - - AppCenter.Start("45774462-9ea7-438a-96fc-03982666f39e", typeof(Analytics)); - AppCenter.SetCountryCode(SettingsStorage.Region); - - sw.Start(); - - SecretsVault.Initialize(); - DownloadAgent.Initialize(); - - if (SettingsStorage.ProcessClipboard) - { - Clipboard.ContentChanged += ParseClipboard; - ParseClipboard(); - } - - PromptFeedback(); - }); - - public static void SuspendApp() - { - sw.Stop(); - SettingsStorage.Uptime += sw.Elapsed; - - HistorySet.Save(); - SettingsStorage.SaveData(); - DownloadAgent.QuitPrompt(); - ManifestGenerator.ClearRoaming(); - Analytics.TrackEvent("Session terminated", new Dictionary - { - { "Uptime", sw.Elapsed.ToString() }, - { "Total time", SettingsStorage.Uptime.ToString() } - }); - } - - public static async void ProcessToast(string arg) - { - string[] args = arg.Split('|'); - switch (args[0]) - { - case "changelog": - case "inbox": - Navigation.GoToDeveloper(args[1]); - break; - - case "video": - Navigation.GoToVideo(args[1]); - break; - - case "channel": - Navigation.GoToChannel(args[1]); - break; - - case "download": - Navigation.GoToDownloads(); - break; - case "dcancel": - DownloadAgent.Cancel(args[1]); - break; - case "clipboard": - switch (args[1]) - { - case "video": - Navigation.GoToVideo(args[2]); - break; - case "channel": - Navigation.GoToChannel(args[2]); - break; - case "playlist": - Navigation.GoToPlaylist(args[2]); - break; - } - break; - case "later": - if (SecretsVault.IsAuthorized) - await Methods.AddItemToWL(args[1]); - else - { - SecretsVault.AuthorizationStateChanged += async (e) => - { - if (e.Value) - await Methods.AddItemToWL(args[1]); - }; - SecretsVault.CheckAuthorization(false); - } - break; - } - } - public static async void PromptFeedback() - { - ResourceLoader resources = ResourceLoader.GetForCurrentView("Main"); - - if (SettingsStorage.Uptime.TotalHours >= 12 && SettingsStorage.PromptFeedback) - { - MessageDialog dialog = new MessageDialog(resources.GetString("/Main/feedbackMessage")); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/dontAsk"), (command) => SettingsStorage.PromptFeedback = false)); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/promptLater"))); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/sure"), async (command) => - { - SettingsStorage.PromptFeedback = false; - if (StoreServicesFeedbackLauncher.IsSupported()) - await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync(); - else - { - MessageDialog message = new MessageDialog(resources.GetString("/Main/feedbackFail")); - message.Commands.Add(new UICommand(resources.GetString("/Main/sendEmail"), async (c) => await Launcher.LaunchUriAsync("mailto:michael.xfox@outlook.com".ToUri()))); - message.Commands.Add(new UICommand(resources.GetString("/Main/goBack"))); - message.CancelCommandIndex = 1; - message.DefaultCommandIndex = 0; - await message.ShowAsync(); - } - })); - dialog.DefaultCommandIndex = 2; - dialog.CancelCommandIndex = 1; - await dialog.ShowAsync(); - } - - if (SettingsStorage.Uptime.TotalHours >= 24 && SettingsStorage.PromptReview) - { - MessageDialog dialog = new MessageDialog(resources.GetString("/Main/rate")); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/dontAsk"), (command) => SettingsStorage.PromptReview = false)); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/promptLater"))); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/sure"), async (command) => - { - SettingsStorage.PromptReview = false; - await Launcher.LaunchUriAsync("ms-windows-store://review/?ProductId=9NCQQXJTDLFH".ToUri()); - })); - dialog.DefaultCommandIndex = 2; - dialog.CancelCommandIndex = 1; - await dialog.ShowAsync(); - } - } - - public static async void ParseClipboard(object sender = null, object e = null) - { - ResourceLoader resources = ResourceLoader.GetForCurrentView("Main"); - - if (Window.Current.CoreWindow.ActivationMode != Windows.UI.Core.CoreWindowActivationMode.ActivatedInForeground || !SettingsStorage.ProcessClipboard) - return; - - try - { - string link = await Clipboard.GetContent().GetTextAsync(); - - if (!link.Contains("youtube") && !link.Contains("youtu.be")) - return; - - string id; - string type = string.Empty; - string name = string.Empty; - - if (YoutubeExplode.YoutubeClient.TryParseChannelId(link, out id)) - { - type = "channel"; - name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title; - } - else if (YoutubeExplode.YoutubeClient.TryParsePlaylistId(link, out id)) - { - type = "playlist"; - name = (await new YoutubeExplode.YoutubeClient().GetPlaylistAsync(id)).Title; - } - else if (YoutubeExplode.YoutubeClient.TryParseUsername(link, out id)) - { - id = await new YoutubeExplode.YoutubeClient().GetChannelIdAsync(id); - type = "channel"; - name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title; - } - else if (YoutubeExplode.YoutubeClient.TryParseVideoId(link, out id)) - { - type = "video"; - name = (await new YoutubeExplode.YoutubeClient().GetVideoAsync(id)).Title; - } - - if(string.IsNullOrWhiteSpace(id)) - return; - - Windows.Data.Xml.Dom.XmlDocument toastXml = new Windows.Data.Xml.Dom.XmlDocument(); - toastXml.LoadXml($@" - - - {resources.GetString("/Main/clipboardHead")} - {name} - {resources.GetString($"/Main/{type}")} - - - - - - "); - ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml)); - } - catch { } - } - - /// - /// Comparing current version with last recorded version. If doesn't match, poping up changelog notification - /// - static async void CheckVersion() - { - PackageVersion ver = Package.Current.Id.Version; - if (SettingsStorage.Version != $"{ver.Major}.{ver.Minor}.{ver.Build}") - try - { - XmlDocument changelog = new XmlDocument(); - StorageFile file = await (await Package.Current.InstalledLocation.GetFolderAsync(@"Assets\Data")).GetFileAsync("Patchnotes.xml"); - changelog.Load(await file.OpenStreamForReadAsync()); - - ToastNotificationManager.CreateToastNotifier().Show(Background.Notification.GetChangelogToast(changelog["items"].FirstChild.Attributes["version"].Value)); - - SettingsStorage.Version = $"{ver.Major}.{ver.Minor}.{ver.Build}"; - } - catch (Exception e) - { - Analytics.TrackEvent("Unable to retrieve changelog", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "App version", $"{ver.Major}.{ver.Minor}.{ver.Revision}.{ver.Build}" }, - { "StackTrace", e.StackTrace } - }); - } - } - - /// - /// Initializes background task for processing toast notifications' clicks - /// - static async void RegisterToastTask() - { - const string taskName = "FoxtubeToastBackground"; - if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals(taskName))) - return; - - var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync(); - if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || backgroundRequest == BackgroundAccessStatus.DeniedByUser) - return; - - BackgroundTaskBuilder builder = new BackgroundTaskBuilder() { Name = taskName }; - builder.SetTrigger(new ToastNotificationActionTrigger()); - - BackgroundTaskRegistration registration = builder.Register(); - } - - /// - /// Initializes background task for checking user's subscriptions and poping toast notifications when new video is uploaded - /// - static async void ActivateBackgoundTask() - { - const string taskName = "FoxtubeBackgound"; - if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals(taskName))) - return; - - var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync(); - var saverRequest = PowerManager.EnergySaverStatus; - if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || backgroundRequest == BackgroundAccessStatus.DeniedByUser || saverRequest == EnergySaverStatus.On) - return; - - BackgroundTaskBuilder builder = new BackgroundTaskBuilder() - { - Name = taskName, - IsNetworkRequested = true, - TaskEntryPoint = "FoxTube.Background.BackgroundProcessor" - }; - builder.SetTrigger(new TimeTrigger(15, false)); - - BackgroundTaskRegistration registration = builder.Register(); - } - } -} diff --git a/FoxTube/Classes/QualityComparer.cs b/FoxTube/Classes/QualityComparer.cs deleted file mode 100644 index 0a3bb90..0000000 --- a/FoxTube/Classes/QualityComparer.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; - -namespace FoxTube.Classes -{ - public class QualityComparer : IComparer - { - public int Compare(string x, string y) - { - string[] xArr = x.Split('p'); - string[] yArr = y.Split('p'); - - int qualityA = int.Parse(xArr[0]); - int qualityB = int.Parse(yArr[0]); - int framerateA = 30; - int framerateB = 30; - - if (!string.IsNullOrWhiteSpace(xArr[1])) - framerateA = int.Parse(xArr[1]); - if (!string.IsNullOrWhiteSpace(yArr[1])) - framerateB = int.Parse(yArr[1]); - - if (qualityA > qualityB) - return 1; - else if (qualityA < qualityB) - return -1; - else - return framerateA - framerateB > 0 ? 1 : -1; - } - } -} diff --git a/FoxTube/Classes/SearchParameters.cs b/FoxTube/Classes/SearchParameters.cs deleted file mode 100644 index bd31364..0000000 --- a/FoxTube/Classes/SearchParameters.cs +++ /dev/null @@ -1,156 +0,0 @@ -using Google.Apis.YouTube.v3.Data; -using System; -using System.Collections.Generic; -using static Google.Apis.YouTube.v3.SearchResource.ListRequest; - -namespace FoxTube -{ - public class SearchParameters - { - public class Filters - { - public static class Enumerations - { - public enum Order { Relevance, Date, Views, Rating, Title } - public enum Type { All, Video, Channel, Playlist } - public enum Date { Any, Hour, Today, Week, Month, Year } - public enum Duration { Any, Long, Medium, Short } - public enum ConversionType { Order, Type, Date, Duration, HD, ThreeD, Captions, LiveEvent, CreativeCommons } - } - - public Enumerations.Order Order { get; set; } = Enumerations.Order.Relevance; - public Enumerations.Date Date { get; set; } = Enumerations.Date.Any; - public Enumerations.Type Type { get; set; } = Enumerations.Type.All; - public Enumerations.Duration Duration { get; set; } = Enumerations.Duration.Any; - public bool HD { get; set; } = false; - public bool Is3D { get; set; } = false; - public bool Captions { get; set; } = false; - public bool LiveEvent { get; set; } = false; - public bool CreativeCommons { get; set; } = false; - - public object GetParameter(Enumerations.ConversionType type) - { - switch(type) - { - case Enumerations.ConversionType.Captions: - if (Captions) - return VideoCaptionEnum.ClosedCaption; - else return VideoCaptionEnum.Any; - case Enumerations.ConversionType.CreativeCommons: - if (CreativeCommons) - return VideoLicenseEnum.CreativeCommon; - else return VideoLicenseEnum.Any; - case Enumerations.ConversionType.Date: - switch(Date) - { - case Enumerations.Date.Any: - return null; - case Enumerations.Date.Hour: - return DateTime.Now.Subtract(TimeSpan.FromHours(1)); - case Enumerations.Date.Today: - return DateTime.Now.Subtract(TimeSpan.FromDays(1)); - case Enumerations.Date.Week: - return DateTime.Now.Subtract(TimeSpan.FromDays(7)); - case Enumerations.Date.Month: - return DateTime.Now.Subtract(TimeSpan.FromDays(31)); - case Enumerations.Date.Year: - return DateTime.Now.Subtract(TimeSpan.FromDays(365)); - } - break; - case Enumerations.ConversionType.Duration: - return (VideoDurationEnum)Duration; - case Enumerations.ConversionType.HD: - if (HD) - return VideoDefinitionEnum.High; - else return VideoDefinitionEnum.Any; - case Enumerations.ConversionType.LiveEvent: - if (LiveEvent) - return EventTypeEnum.Live; - else return null; - case Enumerations.ConversionType.Order: - Dictionary d = new Dictionary() - { - { 0, 2 }, - { 1, 0 }, - { 2, 5 }, - { 3, 1 }, - { 4, 3 } - }; - return (OrderEnum)d[(int)Order]; - case Enumerations.ConversionType.ThreeD: - if (Is3D) - return VideoDimensionEnum.Value3d; - else return VideoDimensionEnum.Any; - case Enumerations.ConversionType.Type: - switch(Type) - { - case Enumerations.Type.All: - return "video,channel,playlist"; - case Enumerations.Type.Channel: - return "channel"; - case Enumerations.Type.Playlist: - return "playlist"; - case Enumerations.Type.Video: - return "video"; - } - break; - } - return null; - } - } - - public string Term { get; private set; } - public string Channel { get; private set; } - public VideoCategory Category { get; set; } - public Filters Filter { get; private set; } = new Filters(); - - public SearchParameters(string term) - { - Term = term; - } - - public SearchParameters(VideoCategory category) - { - Category = category; - Filter = new Filters(); - Filter.Type = Filters.Enumerations.Type.Video; - } - - public SearchParameters(string term, Filters filters) - { - Term = term; - Filter = filters; - } - - public SearchParameters(string term, string channelId) - { - Term = term; - Channel = channelId; - } - - - public SearchParameters(string term, string channelId, Filters filters) - { - Term = term; - Channel = channelId; - Filter = filters; - } - - public override string ToString() - { - return $@"Term: {Term} -Channel id: {Channel} -Category id: {Category} -Filters: - Order: {Filter.Order} - Type: {Filter.Type} - Date: {Filter.Date} - Duration: {Filter.Duration} - HD: {Filter.HD} - 3D: {Filter.Is3D} - Event type: {Filter.LiveEvent} - CC: {Filter.Captions} - License: {Filter.CreativeCommons}"; - } - } -} diff --git a/FoxTube/Classes/SecretsVault.cs b/FoxTube/Classes/SecretsVault.cs deleted file mode 100644 index 5bf49a1..0000000 --- a/FoxTube/Classes/SecretsVault.cs +++ /dev/null @@ -1,275 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Google.Apis.Auth.OAuth2; -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using Windows.Services.Store; -using System.Net.Http; -using Google.Apis.Oauth2.v2.Data; -using Google.Apis.Oauth2.v2; -using static Google.Apis.Auth.OAuth2.UwpCodeReceiver; -using Microsoft.AppCenter.Analytics; -using System.Net; -using FoxTube.Classes; -using System.Linq; - -namespace FoxTube -{ - public static class SecretsVault - { - #region Properties - //Events - public static event AuthorizationChangedEventHandler AuthorizationStateChanged; - public static event SubscriptionsChangedEventHandler SubscriptionsChanged; - public static event ObjectEventHandler Purchased; //Rising when app finds out that it's not a PRO version or after purchase - - //Properties - public static NetworkCredential EmailCredential => new NetworkCredential("foxtube.bot@xfox111.net", "JkY39w$.7?bT57O,8k3a"); - private static ClientSecrets Secrets => new ClientSecrets - { - ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com", - ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_" - }; - private static YouTubeService NoAuthService => new YouTubeService(new BaseClientService.Initializer - { - ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0", - ApplicationName = "FoxTube" - }); - private static BaseClientService.Initializer Initializer => new BaseClientService.Initializer - { - HttpClientInitializer = Credential, - ApplicationName = "FoxTube" - }; - public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService; - - public static HttpClient HttpClient { get; } = new HttpClient(); - private static bool TestAds => true; //TODO: Change this bool - public static string AppId => TestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh"; - public static string AdUnitId => TestAds ? "test" : "1100037769"; - public static bool AdsDisabled { get; private set; } = true; - - //User info - public static bool IsAuthorized => Credential != null; - private static UserCredential Credential { get; set; } = null; - - public static string AccountId => UserChannel?.Id; - public static Channel UserChannel { get; private set; } - public static Userinfoplus UserInfo { get; private set; } - - public static List Subscriptions { get; } = new List(); - public static YoutubeExplode.Models.Playlist History { get; set; } - public static YoutubeExplode.Models.Playlist WatchLater { get; set; } - #endregion - - #region Methods - public static void RefreshToken() => - Credential?.RefreshTokenAsync(CancellationToken.None); - - /// - /// Subscribes or unsibscribes authorized user from the channel - /// - /// The ID of channel which has to be added/removed - /// Returns 'true' if channel is in subscriptions now; 'false' if it's not - public static async Task ChangeSubscriptionState(string id) - { - if(Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == id) is Subscription subscription) - { - try { await Service.Subscriptions.Delete(subscription.Id).ExecuteAsync(); } - catch { return true; } - - SubscriptionsChanged?.Invoke("remove", subscription); - Subscriptions.Remove(subscription); - - return false; - } - else - { - var request = Service.Subscriptions.Insert(new Subscription - { - Snippet = new SubscriptionSnippet - { - ResourceId = new ResourceId - { - ChannelId = id, - Kind = "youtube#channel" - } - } - }, "snippet"); - - if (!(await request.ExecuteAsync() is Subscription sub)) - return false; - - Subscriptions.Add(sub); - SubscriptionsChanged?.Invoke("add", sub); - - return true; - } - } - - /// - /// Sets up **SecretsVault** - /// - public static void Initialize() - { - CheckAddons(); - CheckAuthorization(); - } - - /// - /// Prompts to add an Youtube account and retrieves its info when successful - /// - /// Loads user's subscriptions if true - public static async void Authorize(bool retrieveSubs = true) - { - #region Retrieving user's credential - try - { - Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( - Secrets, - new[] - { - Oauth2Service.Scope.UserinfoProfile, - Oauth2Service.Scope.UserinfoEmail, - YouTubeService.Scope.YoutubeForceSsl, - YouTubeService.Scope.YoutubeUpload - }, - "user", - CancellationToken.None); - - await Credential.RefreshTokenAsync(CancellationToken.None); - } - catch (AuthenticateException e) when (e.Message.Contains("UserCancel")) { } - catch(Exception e) - { - AuthorizationStateChanged?.Invoke(null); - Analytics.TrackEvent("Failed to authorize", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "StackTrace", e.StackTrace } - }); - } - - if (Credential == null || !retrieveSubs) - return; - - HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Credential.Token.AccessToken); - - SettingsStorage.HasAccount = true; - #endregion - - try - { - #region Retrieving user's data - UserInfo = await new Oauth2Service(Initializer).Userinfo.Get().ExecuteAsync(); - - WatchLater = await Methods.GetLater(); - History = await Methods.GetHistory(); - - SubscriptionsResource.ListRequest subRequest = Service.Subscriptions.List("snippet"); - subRequest.Mine = true; - subRequest.MaxResults = 50; - subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance; - SubscriptionListResponse subResponse; - string nextToken = null; - - do - { - subRequest.PageToken = nextToken; - subResponse = await subRequest.ExecuteAsync(); - foreach (Subscription s in subResponse.Items) - Subscriptions.Add(s); - nextToken = subResponse.NextPageToken; - - } while (!string.IsNullOrWhiteSpace(nextToken)); - - ChannelsResource.ListRequest request = Service.Channels.List("snippet,contentDetails"); - request.Mine = true; - UserChannel = (await request.ExecuteAsync()).Items.FirstOrDefault(); - #endregion - - AuthorizationStateChanged?.Invoke(true); - } - catch (Exception e) - { - AuthorizationStateChanged?.Invoke(null); - Methods.SendMail(e.ToString()); - Analytics.TrackEvent("Failed to retrieve user's info", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "StackTrace", e.StackTrace } - }); - } - } - - /// - /// Deauthenticates current user - /// - public static async void Deauthenticate() - { - if (!await Credential.RevokeTokenAsync(CancellationToken.None)) - return; - - Credential = null; - UserChannel = null; - UserInfo = null; - History = null; - WatchLater = null; - Subscriptions.Clear(); - - HttpClient.DefaultRequestHeaders.Authorization = null; - - AuthorizationStateChanged?.Invoke(false); - SettingsStorage.HasAccount = false; - } - - /// - /// Checks if any user has already been logged in. If has, calls *Authorize()* to retrieve his info - /// - /// Loads user's subscriptions if true - public static void CheckAuthorization(bool retrieveSubs = true) - { - if (SettingsStorage.HasAccount) - Authorize(retrieveSubs); - else - AuthorizationStateChanged.Invoke(false); - } - - /// - /// Connects to MS Store and checks if user has bought ad-free - /// - public static async void CheckAddons() - { - try - { - StoreProductQueryResult requset = await StoreContext.GetDefault().GetAssociatedStoreProductsAsync(new[] { "Durable" }); - - if (requset.Products["9NP1QK556625"].IsInUserCollection) - return; - - AdsDisabled = false; - Purchased?.Invoke(null, false, requset.Products["9NP1QK556625"].Price.FormattedPrice); - } - catch { } - } - - public static async void GetAdblock() - { - StorePurchaseResult request = await StoreContext.GetDefault().RequestPurchaseAsync("9NP1QK556625"); - - switch (request.Status) - { - case StorePurchaseStatus.AlreadyPurchased: - case StorePurchaseStatus.Succeeded: - Purchased?.Invoke(args: true); - AdsDisabled = true; - break; - } - } - #endregion - } -} diff --git a/FoxTube/Classes/SettingsStorage.cs b/FoxTube/Classes/SettingsStorage.cs deleted file mode 100644 index 52f545c..0000000 --- a/FoxTube/Classes/SettingsStorage.cs +++ /dev/null @@ -1,286 +0,0 @@ -using Microsoft.AppCenter.Analytics; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using Windows.ApplicationModel; -using Windows.Storage; -using Windows.UI.Xaml.Controls; - -namespace FoxTube -{ - public enum MatureState { Blocked, Allowed } - - public class SettingsContainer - { - public string videoQuality = "remember"; - public string rememberedQuality = "1080p"; - - public bool videoNotifications = true; - public bool devNotifications = true; - - public bool checkConnection = true; - public bool autoplay = true; - public double volume = 100; - - public string language = GetLanguage(); - public string relevanceLanguage = CultureInfo.InstalledUICulture.TwoLetterISOLanguageName; - public string region = CultureInfo.InstalledUICulture.Name.Split('-')[1]; - public int safeSearch = 0; - - public bool hasAccount = false; - public int theme = 2; - - public TimeSpan uptime = TimeSpan.FromSeconds(0); - public bool promptReview = true; - public bool promptFeedback = true; - - public bool processClipboard = true; - public bool minimizeCommandbar = false; - - private static string GetLanguage() - { - if (new string[] { "ru-RU", "en-US" }.Contains(CultureInfo.InstalledUICulture.Name)) - return CultureInfo.InstalledUICulture.Name; - else if ((new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName)) - return "ru-RU"; - else - return "en-US"; - } - } - - public static class SettingsStorage - { - public static string VideoQuality - { - get { return Container.videoQuality; } - set - { - Container.videoQuality = value; - SaveData(); - } - } - public static string RememberedQuality - { - get { return Container.rememberedQuality; } - set - { - Container.rememberedQuality = value; - SaveData(); - } - } - - public static bool VideoNotifications - { - get { return Container.videoNotifications; } - set - { - Container.videoNotifications = value; - SaveData(); - } - } - public static bool DevNotifications - { - get { return Container.devNotifications; } - set - { - Container.devNotifications = value; - SaveData(); - } - } - - public static bool CheckConnection - { - get { return Container.checkConnection; } - set - { - Container.checkConnection = value; - SaveData(); - } - } - public static bool Autoplay - { - get { return Container.autoplay; } - set - { - Container.autoplay = value; - SaveData(); - } - } - public static double Volume - { - get { return Container.volume; } - set - { - Container.volume = value; - SaveData(); - } - } - - public static string Language - { - get { return Container.language; } - set - { - Container.language = value; - SaveData(); - } - } - public static string RelevanceLanguage - { - get { return Container.relevanceLanguage; } - set - { - Container.relevanceLanguage = value; - SaveData(); - } - } - public static string Region - { - get { return Container.region; } - set - { - Container.region = value; - SaveData(); - } - } - public static int SafeSearch - { - get { return Container.safeSearch; } - set - { - Container.safeSearch = value; - SaveData(); - } - } - public static bool HasAccount - { - get { return Container.hasAccount; } - set - { - Container.hasAccount = value; - SaveData(); - } - } - public static int Theme - { - get { return Container.theme; } - set - { - Container.theme = value; - SaveData(); - } - } - - public static string Version - { - get - { - if (storage.Values["version"] == null) - { - PackageVersion ver = Package.Current.Id.Version; - storage.Values["version"] = $"{ver.Major}.{ver.Minor}"; - return $"{ver.Major}.{ver.Minor}"; - } - else return (string)storage.Values["version"]; - } - set - { - storage.Values["version"] = value; - } - } - public static MatureState Mature - { - get - { - if (storage.Values["mature"] == null) - { - storage.Values["mature"] = (int)MatureState.Blocked; - return MatureState.Blocked; - } - else return (MatureState)storage.Values["mature"]; - } - set - { - storage.Values["mature"] = value; - } - } - - public static TimeSpan Uptime - { - get { return Container.uptime; } - set - { - Container.uptime = value; - SaveData(); - } - } - public static bool PromptReview - { - get { return Container.promptReview; } - set - { - Container.promptReview = value; - SaveData(); - } - } - public static bool PromptFeedback - { - get { return Container.promptFeedback; } - set - { - Container.promptFeedback = value; - SaveData(); - } - } - - public static bool ProcessClipboard - { - get => Container.processClipboard; - set - { - Container.processClipboard = value; - SaveData(); - } - } - - public static AppBarClosedDisplayMode AppBarClosedMode - { - get => Container.minimizeCommandbar ? AppBarClosedDisplayMode.Minimal : AppBarClosedDisplayMode.Compact; - set - { - Container.minimizeCommandbar = value == AppBarClosedDisplayMode.Minimal; - SaveData(); - } - } - - //Settings storage - private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings; - private static SettingsContainer Container = new SettingsContainer(); - - public static void LoadData() - { - try - { - Container = JsonConvert.DeserializeObject(storage.Values["settings"] as string); - } - catch (Exception e) - { - SaveData(); - if (storage.Values["settings"] != null) - Analytics.TrackEvent("Failed to retrieve settings", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "StackTrace", e.StackTrace } - }); - } - } - - public static void SaveData() - { - storage.Values["settings"] = JsonConvert.SerializeObject(Container); - } - } -} diff --git a/FoxTube/Classes/StreamInfo.cs b/FoxTube/Classes/StreamInfo.cs deleted file mode 100644 index b906d03..0000000 --- a/FoxTube/Classes/StreamInfo.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace FoxTube.Classes -{ - public class StreamInfo - { - public class VideoInfo - { - public string IndexRange { get; set; } - public string InitRange => $"0-{int.Parse(IndexRange.Split('-')[0]) - 1}"; - public string Itag { get; set; } - public string Fps { get; set; } - public string Url { get; set; } - public string Codecs { get; set; } - public string MimeType { get; set; } - public string Height { get; set; } - public string Width { get; set; } - public string Label { get; set; } - } - public class AudioInfo - { - public string IndexRange { get; set; } - public string InitRange => $"0-{int.Parse(IndexRange.Split('-')[0]) - 1}"; - public string SampleRate { get; set; } - public string ChannelsCount { get; set; } - public string Codecs { get; set; } - public string MimeType { get; set; } - public string Url { get; set; } - public string Itag { get; set; } - } - - public List Video { get; } = new List(); - public List Audio { get; } = new List(); - } - - public class StreamQuality - { - public Uri Url { get; set; } - public string Resolution { get; set; } - } -} diff --git a/FoxTube/Controls/Adverts/CardAdvert.xaml b/FoxTube/Controls/Adverts/CardAdvert.xaml deleted file mode 100644 index 038beec..0000000 --- a/FoxTube/Controls/Adverts/CardAdvert.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FoxTube/Controls/Adverts/CardAdvert.xaml.cs b/FoxTube/Controls/Adverts/CardAdvert.xaml.cs deleted file mode 100644 index 55274af..0000000 --- a/FoxTube/Controls/Adverts/CardAdvert.xaml.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Linq; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Microsoft.Advertising.WinRT.UI; -using Windows.UI.Xaml.Media.Imaging; -using Microsoft.Toolkit.Uwp.UI.Controls; - -namespace FoxTube.Controls.Adverts -{ - /// - /// Advert which is looks similar to video cards - /// - public sealed partial class CardAdvert : UserControl - { - readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId); - NativeAdV2 advert; - public CardAdvert() - { - InitializeComponent(); - manager.AdReady += AdReady; - manager.ErrorOccurred += ErrorOccurred; - manager.RequestAd(); - } - - void ErrorOccurred(object sender, NativeAdErrorEventArgs e) - { - (Parent as AdaptiveGridView)?.Items.Remove(this); - System.Diagnostics.Debug.WriteLine("Error has occured while loading ad"); - } - - void AdReady(object sender, NativeAdReadyEventArgs e) - { - advert = e.NativeAd; - Initialize(); - e.NativeAd.RegisterAdContainer(grid); - } - - void Initialize() - { - title.Text = advert.Title; - image.Source = new BitmapImage(advert.MainImages.First().Url.ToUri()); - - icon.ProfilePicture = advert.AdIcon == null ? null : advert.AdIcon.Source; - - sponsor.Text = Methods.GuardFromNull(advert.SponsoredBy); - - if (string.IsNullOrWhiteSpace(advert.CallToActionText)) - (info.Parent as FrameworkElement).Visibility = Visibility.Collapsed; - else - info.Text = advert.CallToActionText; - - desc.Text = string.Empty; - - if (!string.IsNullOrWhiteSpace(advert.Price)) - desc.Text += advert.Price; - - if (!string.IsNullOrWhiteSpace(advert.Rating)) - desc.Text += " " + advert.Rating; - } - - void Image_ImageOpened(object sender, RoutedEventArgs e) => - show.Begin(); - } -} diff --git a/FoxTube/Controls/Adverts/ChatAdvert.xaml b/FoxTube/Controls/Adverts/ChatAdvert.xaml deleted file mode 100644 index 01b673d..0000000 --- a/FoxTube/Controls/Adverts/ChatAdvert.xaml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FoxTube/Controls/Adverts/ChatAdvert.xaml.cs b/FoxTube/Controls/Adverts/ChatAdvert.xaml.cs deleted file mode 100644 index 986722f..0000000 --- a/FoxTube/Controls/Adverts/ChatAdvert.xaml.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Microsoft.Advertising.WinRT.UI; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Foundation; -using Windows.Foundation.Collections; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; -using Windows.UI.Xaml.Data; -using Windows.UI.Xaml.Input; -using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Navigation; - -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - -namespace FoxTube.Controls.Adverts -{ - public sealed partial class ChatAdvert : ListViewItem - { - readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId); - NativeAdV2 advert; - - public ChatAdvert() - { - InitializeComponent(); - - manager.AdReady += AdReady; - manager.RequestAd(); - } - - void AdReady(object sender, NativeAdReadyEventArgs e) - { - advert = e.NativeAd; - Initialize(); - if (cta.Visibility == Visibility.Collapsed) - e.NativeAd.RegisterAdContainer(grid); - else - e.NativeAd.RegisterAdContainer(grid, new List { cta }); - } - - void Initialize() - { - name.Text = Methods.GuardFromNull(advert.SponsoredBy); - ToolTipService.SetToolTip(name, name.Text); - - icon.ProfilePicture = advert.AdIcon == null ? null : advert.AdIcon.Source; - title.Text = advert.Title; - - description.Text = Methods.GuardFromNull(advert.Description); - - cta.Text = Methods.GuardFromNull(advert.CallToActionText); - cta.Visibility = string.IsNullOrWhiteSpace(advert.CallToActionText) ? Visibility.Collapsed : Visibility.Visible; - - Visibility = Visibility.Visible; - } - } -} diff --git a/FoxTube/Controls/Adverts/CommentAdvert.xaml b/FoxTube/Controls/Adverts/CommentAdvert.xaml deleted file mode 100644 index b8bc141..0000000 --- a/FoxTube/Controls/Adverts/CommentAdvert.xaml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FoxTube/Controls/VideoPage/Comments.xaml.cs b/FoxTube/Controls/VideoPage/Comments.xaml.cs deleted file mode 100644 index 2893afb..0000000 --- a/FoxTube/Controls/VideoPage/Comments.xaml.cs +++ /dev/null @@ -1,196 +0,0 @@ -using System; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using FoxTube.Controls; -using Windows.UI.Popups; -using Windows.ApplicationModel.Resources; -using Microsoft.AppCenter.Analytics; -using System.Collections.Generic; - -namespace FoxTube.Controls.VideoPage -{ - /// - /// Comments placeholder - /// - public sealed partial class Comments : UserControl - { - ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage"); - - string threadId; - string token; - - CommentThreadsResource.ListRequest.OrderEnum order = CommentThreadsResource.ListRequest.OrderEnum.Relevance; - CommentThreadsResource.ListRequest request; - - public Comments() - { - InitializeComponent(); - } - - public async void Initialize(Video video) - { - threadId = video.Id; - Methods.CommentsPage = this; - - if (!SecretsVault.IsAuthorized) - grid.RowDefinitions[0].Height = new GridLength(0); - - counter.Text = $"{video.Statistics.CommentCount:0,0} {resources.GetString("/CommentsPage/comments")}"; - orderBtn.Content = resources.GetString("/CommentsPage/relevance/Text"); - - request = SecretsVault.Service.CommentThreads.List("snippet,replies"); - request.MaxResults = 25; - request.Order = order; - request.VideoId = video.Id; - request.TextFormat = CommentThreadsResource.ListRequest.TextFormatEnum.PlainText; - - var response = await request.ExecuteAsync(); - - token = response.NextPageToken; - if (string.IsNullOrWhiteSpace(token)) - more.Visibility = Visibility.Collapsed; - - foreach (CommentThread comment in response.Items) - { - if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) - list.Children.Add(new Controls.Adverts.CommentAdvert()); - list.Children.Add(new CommentCard(comment)); - } - } - - public void RemoveComment(CommentCard commentCard, string topCommentId = null) - { - if (string.IsNullOrWhiteSpace(topCommentId)) - list.Children.Remove(commentCard); - else - (list.Children.Find(i => (i as CommentCard).thread.Id == topCommentId) as CommentCard)?.DeleteComment(commentCard); - } - - private async void toRelevance_Click(object sender, RoutedEventArgs e) - { - if (order == CommentThreadsResource.ListRequest.OrderEnum.Relevance) - return; - - more.Visibility = Visibility.Visible; - - order = CommentThreadsResource.ListRequest.OrderEnum.Relevance; - orderBtn.Content = resources.GetString("/CommentsPage/relevance/Text"); - - list.Children.Clear(); - - request.Order = order; - var response = await request.ExecuteAsync(); - - token = response.NextPageToken; - if (string.IsNullOrWhiteSpace(token)) - more.Visibility = Visibility.Collapsed; - - foreach (CommentThread comment in response.Items) - { - if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) - list.Children.Add(new Controls.Adverts.CommentAdvert()); - list.Children.Add(new CommentCard(comment)); - } - - more.Complete(); - } - - private async void toDate_Click(object sender, RoutedEventArgs e) - { - if (order == CommentThreadsResource.ListRequest.OrderEnum.Time) - return; - - more.Visibility = Visibility.Visible; - - order = CommentThreadsResource.ListRequest.OrderEnum.Time; - orderBtn.Content = resources.GetString("/CommentsPage/publish"); - - list.Children.Clear(); - - request.Order = order; - var response = await request.ExecuteAsync(); - - token = response.NextPageToken; - if (string.IsNullOrWhiteSpace(token)) - more.Visibility = Visibility.Collapsed; - - foreach (CommentThread comment in response.Items) - { - if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) - list.Children.Add(new Controls.Adverts.CommentAdvert()); - list.Children.Add(new CommentCard(comment)); - } - - more.Complete(); - } - - private async void send_Click(object sender, RoutedEventArgs args) - { - if (string.IsNullOrWhiteSpace(newComment.Text)) - return; - - newComment.IsEnabled = false; - send.IsEnabled = false; - sending.Visibility = Visibility.Visible; - - CommentThread thread = new CommentThread - { - Snippet = new CommentThreadSnippet - { - TopLevelComment = new Comment - { - Snippet = new CommentSnippet - { - TextOriginal = newComment.Text - } - }, - VideoId = threadId - } - }; - - try - { - CommentThread response = await SecretsVault.Service.CommentThreads.Insert(thread, "snippet").ExecuteAsync(); - list.Children.Insert(0, new CommentCard(response)); - newComment.Text = ""; - scroll.ChangeView(null, 0, null); - } - catch (Exception e) - { - await new MessageDialog("Failed to publish your comment. Please, try again later.").ShowAsync(); - Analytics.TrackEvent("Failed to post comment", new Dictionary - { - { "Exception", e.GetType().ToString() }, - { "Message", e.Message }, - { "Thread ID", threadId }, - { "StackTrace", e.StackTrace } - }); - } - - newComment.IsEnabled = true; - send.IsEnabled = true; - sending.Visibility = Visibility.Collapsed; - } - - private async void ShowMore_Clicked() - { - request.PageToken = token; - var response = await request.ExecuteAsync(); - - token = response.NextPageToken; - if (string.IsNullOrWhiteSpace(token)) - more.Visibility = Visibility.Collapsed; - - foreach (CommentThread comment in response.Items) - { - if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) - list.Children.Add(new Controls.Adverts.CommentAdvert()); - list.Children.Add(new CommentCard(comment)); - } - - more.Complete(); - } - } -} diff --git a/FoxTube/Controls/VideoPage/RelatedVideos.xaml b/FoxTube/Controls/VideoPage/RelatedVideos.xaml deleted file mode 100644 index ed418a8..0000000 --- a/FoxTube/Controls/VideoPage/RelatedVideos.xaml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - diff --git a/FoxTube/Controls/VideoPage/RelatedVideos.xaml.cs b/FoxTube/Controls/VideoPage/RelatedVideos.xaml.cs deleted file mode 100644 index 7c94e88..0000000 --- a/FoxTube/Controls/VideoPage/RelatedVideos.xaml.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using Windows.UI.Xaml.Controls; - -namespace FoxTube.Controls.VideoPage -{ - public sealed partial class RelatedVideos : UserControl - { - public RelatedVideos() => - InitializeComponent(); - - public async void Initialize(string id) - { - list.Clear(); - - SearchResource.ListRequest request = SecretsVault.Service.Search.List("id"); - request.RegionCode = SettingsStorage.Region; - request.RelevanceLanguage = SettingsStorage.RelevanceLanguage; - request.RelatedToVideoId = id; - request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch; - request.MaxResults = 10; - request.Type = "video"; - - SearchListResponse response = await request.ExecuteAsync(); - - foreach (SearchResult video in response.Items) - list.Add(new VideoCard(video.Id.VideoId)); - - list.Children.Insert(1, new Adverts.CardAdvert()); - } - - public void OpenNext() => - (list.Children[0] as VideoCard).ItemClicked(); - } -} diff --git a/FoxTube/Controls/VideoPage/ReportVideo.xaml b/FoxTube/Controls/VideoPage/ReportVideo.xaml deleted file mode 100644 index e5f2dd2..0000000 --- a/FoxTube/Controls/VideoPage/ReportVideo.xaml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - diff --git a/FoxTube/Controls/VideoPage/ReportVideo.xaml.cs b/FoxTube/Controls/VideoPage/ReportVideo.xaml.cs deleted file mode 100644 index 7b1272f..0000000 --- a/FoxTube/Controls/VideoPage/ReportVideo.xaml.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Windows.UI.Xaml.Controls; -using Google.Apis.YouTube.v3.Data; -using Google.Apis.YouTube.v3; -using Windows.UI.Xaml; -using System; -using Windows.UI.Popups; -using Windows.ApplicationModel.Resources; - -namespace FoxTube.Controls -{ - public sealed partial class ReportVideo : ContentDialog - { - string videoId; - public ReportVideo(string id) - { - InitializeComponent(); - Initialize(); - videoId = id; - } - - async void Initialize() - { - VideoAbuseReportReasonsResource.ListRequest req = SecretsVault.Service.VideoAbuseReportReasons.List("id,snippet"); - req.Hl = SettingsStorage.RelevanceLanguage; - VideoAbuseReportReasonListResponse reasons = await req.ExecuteAsync(); - - foreach (VideoAbuseReportReason i in reasons.Items) - primaryReason.Items.Add(new ComboBoxItem - { - Tag = i, - Content = i.Snippet.Label - }); - } - - private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) - { - VideoAbuseReport report = new VideoAbuseReport - { - Comments = Methods.GuardFromNull(comment.Text), - VideoId = videoId, - ReasonId = ((primaryReason.SelectedItem as ComboBoxItem).Tag as VideoAbuseReportReason).Id, - SecondaryReasonId = secondaryReason.SelectedItem == null ? null : (secondaryReason.SelectedItem as ComboBoxItem).Tag as string - }; - - ResourceLoader resources = ResourceLoader.GetForCurrentView("Report"); - try { await SecretsVault.Service.Videos.ReportAbuse(report).ExecuteAsync(); } - catch - { - await new MessageDialog(resources.GetString("/Report/err")).ShowAsync(); - return; - } - await new MessageDialog(resources.GetString("/Report/submittedHeader"), resources.GetString("/Report/submittedBody")).ShowAsync(); - } - - private void PrimaryReason_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - IsPrimaryButtonEnabled = true; - secondaryReason.Items.Clear(); - foreach (VideoAbuseReportSecondaryReason i in ((primaryReason.SelectedItem as ComboBoxItem).Tag as VideoAbuseReportReason).Snippet.SecondaryReasons) - secondaryReason.Items.Add(new ComboBoxItem - { - Tag = i.Id, - Content = i.Label - }); - - secondaryReason.Visibility = secondaryReason.Items.Count == 0 ? Visibility.Collapsed : Visibility.Visible; - } - } -} diff --git a/FoxTube/Controls/VideoPage/VideoPlaylist.xaml b/FoxTube/Controls/VideoPage/VideoPlaylist.xaml deleted file mode 100644 index 7f656c1..0000000 --- a/FoxTube/Controls/VideoPage/VideoPlaylist.xaml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FoxTube/Controls/VideoPage/VideoPlaylist.xaml.cs b/FoxTube/Controls/VideoPage/VideoPlaylist.xaml.cs deleted file mode 100644 index 92effeb..0000000 --- a/FoxTube/Controls/VideoPage/VideoPlaylist.xaml.cs +++ /dev/null @@ -1,124 +0,0 @@ -using FoxTube.Classes; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Windows.ApplicationModel.Resources; -using Windows.UI.Xaml.Controls; - -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - -namespace FoxTube.Controls.VideoPage -{ - public sealed partial class VideoPlaylist : UserControl - { - public class PlaylistItem - { - public int Number { get; } - public string Id { get; } - public string Title { get; } - public string Thumbnail { get; } - - public PlaylistItem(int number, Google.Apis.YouTube.v3.Data.PlaylistItem item) - { - Number = number; - Id = item.Snippet.ResourceId.VideoId; - Title = item.Snippet.Title; - Thumbnail = item.Snippet.Thumbnails.Medium.Url; - } - - public PlaylistItem(int number, Video item) - { - Number = number; - Id = item.Id; - Title = item.Snippet.Title; - Thumbnail = item.Snippet.Thumbnails.Medium.Url; - } - } - - ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage"); - public event PlaylistItemChangedEventHandler ItemChanged; - - public VideoPlaylist() => - InitializeComponent(); - - public ItemCollection Items => list.Items; - public int SelectedIndex => list.SelectedIndex; - - public async Task Initialize(Video video, string playlist) - { - if (video.Id == "WL") - { - List