├── src └── TumblThree │ ├── TumblThree.Presentation │ ├── Resources │ │ ├── Images │ │ │ ├── About.png │ │ │ ├── Pause.png │ │ │ ├── Play.png │ │ │ ├── Scan.png │ │ │ ├── Stop.png │ │ │ ├── AddBlog.png │ │ │ ├── AddQueue.png │ │ │ ├── Download.png │ │ │ ├── Explorer.png │ │ │ ├── Resume.png │ │ │ ├── Settings.png │ │ │ ├── Tumblr.ico │ │ │ ├── Tumblr.png │ │ │ ├── Clipboard.png │ │ │ ├── RemoveBlog.png │ │ │ └── RemoveQueue.png │ │ ├── TextBoxResources.xaml │ │ ├── LayoutResources.xaml │ │ ├── BrushResources.xaml │ │ └── ConverterResources.xaml │ ├── Controls │ │ ├── RatingItemState.cs │ │ ├── HorizontalFlyoutAlignment.cs │ │ ├── SuperToolTip.cs │ │ └── FocusAdvancement.cs │ ├── DesignData │ │ ├── MockView.cs │ │ ├── SampleBlogFile.cs │ │ ├── SampleAboutViewModel.cs │ │ ├── MockSelectionService.cs │ │ ├── MockManagerService.cs │ │ ├── SampleShellViewModel.cs │ │ ├── SampleDetailsViewModel.cs │ │ └── MockShellService.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── CodeAnalysisDictionary.xml │ │ ├── Settings.settings │ │ └── Settings.Designer.cs │ ├── Services │ │ ├── ClipboardService.cs │ │ ├── PresentationService.cs │ │ └── EnvironmentService.cs │ ├── Themes │ │ ├── Generic.xaml │ │ └── Generic │ │ │ └── SuperToolTip.xaml │ ├── Converters │ │ ├── ConverterHelper.cs │ │ ├── DateToDisplayValueConverter.cs │ │ ├── TotalImageConverter.cs │ │ ├── IntToDisplayValueConverter.cs │ │ ├── BlogTitleConverter.cs │ │ ├── NullToVisibilityConverter.cs │ │ ├── StatusToBoolConverter.cs │ │ ├── ItemsCountConverter.cs │ │ ├── BlogQueueProgressConverter.cs │ │ ├── IsLessThanConverter.cs │ │ ├── IsQueueItemCrawlingMultiConverter.cs │ │ ├── InverseBooleanConverter.cs │ │ ├── BlogQueueInfoConverter.cs │ │ ├── IsBlogInQueueMultiConverter.cs │ │ ├── NullImageConverter.cs │ │ ├── ErrorMessagesConverter.cs │ │ ├── StringListToStringConverter.cs │ │ ├── WindowTitleConverter.cs │ │ ├── DetailsProgressConverter.cs │ │ ├── RatingToStarsConverter.cs │ │ └── BlogtypeToDisplayValueConverter.cs │ ├── ValidationRules │ │ ├── TimeSpanRule.cs │ │ ├── IntRangeRule.cs │ │ └── BandwidthRangeRule.cs │ ├── Views │ │ ├── CrawlerView.xaml.cs │ │ ├── AboutView.xaml.cs │ │ ├── DetailsViews │ │ │ ├── DetailsAllView.xaml.cs │ │ │ ├── DetailsTumblrBlogView.xaml.cs │ │ │ ├── DetailsTumblrSearchView.xaml.cs │ │ │ ├── DetailsTumblrLikedByView.xaml.cs │ │ │ ├── DetailsTumblrTagSearchView.xaml.cs │ │ │ └── DetailsTumblrHiddenBlogView.xaml.cs │ │ ├── AuthenticateView.xaml │ │ ├── SettingsView.xaml.cs │ │ ├── FullScreenMediaView.xaml.cs │ │ └── ShellWindow.xaml.cs │ ├── DispatcherHelper.cs │ ├── App.xaml │ ├── App.config │ └── Extensions │ │ └── EnumBindingSourceExtension.cs │ ├── TumblThree.Applications │ ├── Views │ │ ├── IQueueView.cs │ │ ├── ICrawlerView.cs │ │ ├── IDetailsView.cs │ │ ├── IAboutView.cs │ │ ├── IFullScreenMediaView.cs │ │ ├── ISettingsView.cs │ │ ├── IManagerView.cs │ │ ├── IAuthenticateView.cs │ │ └── IShellView.cs │ ├── DataModels │ │ ├── TumblrCrawlerData │ │ │ ├── ITumblrCrawlerData.cs │ │ │ └── TumblrCrawlerData.cs │ │ ├── DownloadProgress.cs │ │ ├── IPostQueue.cs │ │ ├── TumblrPosts │ │ │ ├── LinkPost.cs │ │ │ ├── TextPost.cs │ │ │ ├── AudioPost.cs │ │ │ ├── PhotoPost.cs │ │ │ ├── QuotePost.cs │ │ │ ├── VideoPost.cs │ │ │ ├── AnswerPost.cs │ │ │ ├── AudioMetaPost.cs │ │ │ ├── PhotoMetaPost.cs │ │ │ ├── VideoMetaPost.cs │ │ │ ├── ExternalPhotoPost.cs │ │ │ ├── ExternalVideoPost.cs │ │ │ ├── ConversationPost.cs │ │ │ └── TumblrPost.cs │ │ ├── PostQueue.cs │ │ └── TumblrSearchJson.cs │ ├── Services │ │ ├── IClipboardService.cs │ │ ├── IEnvironmentService.cs │ │ ├── IConfirmTumblrPrivacyConsent.cs │ │ ├── ISettingsService.cs │ │ ├── ISettingsProvider.cs │ │ ├── IDetailsService.cs │ │ ├── ILoginService.cs │ │ ├── ApplicationBusyContext.cs │ │ ├── CrawlerServiceExtensions.cs │ │ ├── IApplicationUpdateService.cs │ │ ├── ISelectionService.cs │ │ ├── ISharedCookieService.cs │ │ ├── IFolderBrowserDialog.cs │ │ ├── ShellServiceExtensions.cs │ │ ├── IBlogService.cs │ │ ├── IManagerService.cs │ │ ├── IPresentationService.cs │ │ ├── IWebRequestFactory.cs │ │ ├── SelectionService.cs │ │ ├── IShellService.cs │ │ ├── ICrawlerService.cs │ │ └── ManagerService.cs │ ├── Properties │ │ ├── Settings.settings │ │ ├── AssemblyInfo.cs │ │ ├── ManagerSettings.cs │ │ ├── CodeAnalysisDictionary.xml │ │ ├── Settings.Designer.cs │ │ └── QueueSettings.cs │ ├── Parser │ │ ├── ITumblrParser.cs │ │ ├── ICatBoxParser.cs │ │ ├── IUguuParser.cs │ │ ├── ISafeMoeParser.cs │ │ ├── ILoliSafeParser.cs │ │ ├── IMixtapeParser.cs │ │ ├── IWebmshareParser.cs │ │ ├── IGfycatParser.cs │ │ ├── IImgurParser.cs │ │ ├── ITumblrToText.cs │ │ ├── TumblrParser.cs │ │ ├── ITumblrApiXmlToText.cs │ │ ├── UguuParser.cs │ │ ├── SafeMoeParser.cs │ │ ├── CatBoxParser.cs │ │ ├── LoliSafeParser.cs │ │ ├── MixtapeParser.cs │ │ ├── WebmshareParser.cs │ │ ├── TumblrSvcJsonToJson.cs │ │ └── ImgurParser.cs │ ├── Downloader │ │ ├── ICrawlerDataDownloader.cs │ │ └── IDownloader.cs │ ├── Crawler │ │ ├── ITumblrBlogDetector.cs │ │ ├── ICrawler.cs │ │ └── ICrawlerFactory.cs │ ├── ViewModels │ │ ├── IDetailsViewModel.cs │ │ ├── FullScreenMediaViewModel.cs │ │ ├── CrawlerViewModel.cs │ │ └── AuthenticateViewModel.cs │ ├── App.config │ ├── Extensions │ │ └── TaskTimeoutExtension.cs │ ├── Data │ │ ├── SupportedFileTypes.cs │ │ └── StringListConverter.cs │ └── ProgressThrottler.cs │ ├── TumblThree.Domain │ ├── Models │ │ ├── ICrawlerData.cs │ │ ├── IBlogFactory.cs │ │ ├── BlogTypes.cs │ │ ├── Files │ │ │ ├── TumblrBlogFiles.cs │ │ │ ├── TumblrHiddenBlogFiles.cs │ │ │ ├── TumblrLikedByBlogFiles.cs │ │ │ ├── TumblrSearchBlogFiles.cs │ │ │ ├── TumblrTagSearchBlogFiles.cs │ │ │ └── IFiles.cs │ │ ├── IUrlValidator.cs │ │ ├── MetadataType.cs │ │ ├── UguuTypes.cs │ │ ├── CatboxTypes.cs │ │ ├── LoliSafeTypes.cs │ │ ├── SafeMoeTypes.cs │ │ ├── MixtapeTypes.cs │ │ ├── WebmshareTypes.cs │ │ ├── GfycatType.cs │ │ ├── Blogs │ │ │ ├── TumblrBlog.cs │ │ │ ├── TumblrHiddenBlog.cs │ │ │ ├── TumblrLikedByBlog.cs │ │ │ ├── TumblrTagSearchBlog.cs │ │ │ └── TumblrSearchBlog.cs │ │ ├── PostCounter.cs │ │ ├── BlogFactory.cs │ │ └── UrlValidator.cs │ ├── Properties │ │ ├── Settings.settings │ │ ├── AssemblyInfo.cs │ │ ├── CodeAnalysisDictionary.xml │ │ └── Settings.Designer.cs │ ├── App.config │ ├── Queue │ │ └── QueueListItem.cs │ ├── Attributes │ │ └── LocalizedDescriptionAttribute.cs │ ├── Logger.cs │ └── Converter │ │ └── EnumDescriptionTypeConverter.cs │ └── SharedAssemblyInfo.cs ├── lib ├── WpfApplicationFramework │ └── WpfApplicationFramework │ │ ├── WpfApplicationFramework.csproj.vspscc │ │ ├── Applications │ │ ├── IView.cs │ │ ├── IModuleController.cs │ │ ├── DispatcherHelper.cs │ │ ├── PropertyChangedEventListener.cs │ │ ├── CollectionChangedEventListener.cs │ │ ├── ViewModel.Generic.cs │ │ ├── ViewModel.cs │ │ ├── Services │ │ │ └── FileDialogResult.cs │ │ └── ViewHelper.cs │ │ ├── Foundation │ │ ├── IReadOnlyObservableList.cs │ │ ├── DataErrorInfoExtensions.cs │ │ ├── CollectionHelper.cs │ │ └── ReadOnlyObservableList.cs │ │ ├── Properties │ │ └── AssemblyInfo.cs │ │ ├── WafConfiguration.cs │ │ └── Presentation │ │ ├── ValidationReloadedTracker.cs │ │ └── Converters │ │ └── InvertBooleanConverter.cs └── RateLimiter │ └── RateLimiter │ ├── LongMath.cs │ ├── Properties │ └── AssemblyInfo.cs │ └── SleepingStopwatch.cs ├── .gitattributes └── LICENSE /src/TumblThree/TumblThree.Presentation/Resources/Images/About.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/About.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Pause.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Play.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Scan.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Stop.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/AddBlog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/AddBlog.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/AddQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/AddQueue.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Download.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Explorer.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Resume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Resume.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Settings.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Tumblr.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Tumblr.ico -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Tumblr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Tumblr.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/Clipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/Clipboard.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/RemoveBlog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/RemoveBlog.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/Images/RemoveQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarekJor/TumblThree/master/src/TumblThree/TumblThree.Presentation/Resources/Images/RemoveQueue.png -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/IQueueView.cs: -------------------------------------------------------------------------------- 1 | using System.Waf.Applications; 2 | 3 | namespace TumblThree.Applications.Views 4 | { 5 | public interface IQueueView : IView 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/ICrawlerView.cs: -------------------------------------------------------------------------------- 1 | using System.Waf.Applications; 2 | 3 | namespace TumblThree.Applications.Views 4 | { 5 | public interface ICrawlerView : IView 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/IDetailsView.cs: -------------------------------------------------------------------------------- 1 | using System.Waf.Applications; 2 | 3 | namespace TumblThree.Applications.Views 4 | { 5 | public interface IDetailsView : IView 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrCrawlerData/ITumblrCrawlerData.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.DataModels.TumblrCrawlerData 2 | { 3 | interface ITumblrCrawlerData 4 | { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IClipboardService.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.Services 2 | { 3 | public interface IClipboardService 4 | { 5 | void SetText(string text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/ICrawlerData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TumblThree.Domain.Models 4 | { 5 | public interface ICrawlerData 6 | { 7 | Type BlogType { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/DownloadProgress.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.DataModels 2 | { 3 | public class DownloadProgress 4 | { 5 | public string Progress { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IEnvironmentService.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.Services 2 | { 3 | public interface IEnvironmentService 4 | { 5 | string AppSettingsPath { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Controls/RatingItemState.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Presentation.Controls 2 | { 3 | public enum RatingItemState 4 | { 5 | Empty, 6 | Partial, 7 | Filled 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Controls/HorizontalFlyoutAlignment.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Presentation.Controls 2 | { 3 | public enum HorizontalFlyoutAlignment 4 | { 5 | Left, 6 | Center, 7 | Right 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/TextBoxResources.xaml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/IAboutView.cs: -------------------------------------------------------------------------------- 1 | using System.Waf.Applications; 2 | 3 | namespace TumblThree.Applications.Views 4 | { 5 | public interface IAboutView : IView 6 | { 7 | void ShowDialog(object owner); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DesignData/MockView.cs: -------------------------------------------------------------------------------- 1 | using System.Waf.Applications; 2 | 3 | namespace TumblThree.Presentation.DesignData 4 | { 5 | public class MockView : IView 6 | { 7 | public object DataContext { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IConfirmTumblrPrivacyConsent.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace TumblThree.Applications.Services 4 | { 5 | public interface IConfirmTumblrPrivacyConsent 6 | { 7 | Task ConfirmPrivacyConsent(); 8 | } 9 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/IFullScreenMediaView.cs: -------------------------------------------------------------------------------- 1 | using System.Waf.Applications; 2 | 3 | namespace TumblThree.Applications.Views 4 | { 5 | public interface IFullScreenMediaView : IView 6 | { 7 | void ShowDialog(object owner); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/IBlogFactory.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Domain.Models 2 | { 3 | public interface IBlogFactory 4 | { 5 | bool IsValidTumblrBlogUrl(string blogUrl); 6 | 7 | IBlog GetBlog(string blogUrl, string path); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ISettingsService.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Domain.Models; 2 | 3 | namespace TumblThree.Applications.Services 4 | { 5 | internal interface ISettingsService 6 | { 7 | IBlog TransferGlobalSettingsToBlog(IBlog blog); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DesignData/SampleBlogFile.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Domain.Models; 2 | 3 | namespace TumblThree.Presentation.DesignData 4 | { 5 | public class SampleBlogFile : Blog 6 | { 7 | public SampleBlogFile(string url) 8 | { 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/ITumblrParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace TumblThree.Applications.Crawler 4 | { 5 | public interface ITumblrParser 6 | { 7 | Regex GetTumblrPhotoUrlRegex(); 8 | 9 | Regex GetTumblrVideoUrlRegex(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ISettingsProvider.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.Services 2 | { 3 | internal interface ISettingsProvider 4 | { 5 | T LoadSettings(string fileName) where T : class, new(); 6 | 7 | void SaveSettings(string fileName, object settings); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/ISettingsView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Waf.Applications; 3 | 4 | namespace TumblThree.Applications.Views 5 | { 6 | public interface ISettingsView : IView 7 | { 8 | void ShowDialog(object owner); 9 | 10 | event EventHandler Closed; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/BlogTypes.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Domain.Models 2 | { 3 | public enum BlogTypes 4 | { 5 | tumblr, 6 | tmblrpriv, 7 | instagram, 8 | twitter, 9 | tlb, 10 | tumblrsearch, 11 | tumblrtagsearch, 12 | all 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IDetailsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using TumblThree.Domain.Models; 4 | 5 | namespace TumblThree.Applications.Services 6 | { 7 | public interface IDetailsService 8 | { 9 | void SelectBlogFiles(IReadOnlyList blogFiles); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/IPostQueue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TumblThree.Applications.DataModels 4 | { 5 | public interface IPostQueue 6 | { 7 | void Add(T post); 8 | void CompleteAdding(); 9 | IEnumerable GetConsumingEnumerable(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Windows; 3 | 4 | [assembly: AssemblyTitle("TumblThree.Domain")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] 8 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Windows; 3 | 4 | [assembly: AssemblyTitle("TumblThree.Applications")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] 8 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/ICatBoxParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using TumblThree.Domain.Models; 3 | 4 | namespace TumblThree.Applications.Parser 5 | { 6 | public interface ICatBoxParser 7 | { 8 | Regex GetCatBoxUrlRegex(); 9 | 10 | string CreateCatBoxUrl(string id, string detectedUrl, CatBoxTypes type); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/IUguuParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using TumblThree.Domain.Models; 3 | 4 | namespace TumblThree.Applications.Parser 5 | { 6 | public interface IUguuParser 7 | { 8 | Regex GetUguuUrlRegex(); 9 | 10 | string CreateUguuUrl(string uguuId, string detectedUrl, UguuTypes uguuType); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/WpfApplicationFramework.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/ISafeMoeParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using TumblThree.Domain.Models; 3 | 4 | namespace TumblThree.Applications.Parser 5 | { 6 | public interface ISafeMoeParser 7 | { 8 | Regex GetSafeMoeUrlRegex(); 9 | 10 | string CreateSafeMoeUrl(string id, string detectedUrl, SafeMoeTypes type); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Windows; 3 | 4 | [assembly: AssemblyTitle("TumblThree - A Tumblr Blog Backup Application")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] 8 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/ILoliSafeParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using TumblThree.Domain.Models; 3 | 4 | namespace TumblThree.Applications.Parser 5 | { 6 | public interface ILoliSafeParser 7 | { 8 | Regex GetLoliSafeUrlRegex(); 9 | 10 | string CreateLoliSafeUrl(string id, string detectedUrl, LoliSafeTypes type); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ILoginService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace TumblThree.Applications.Services 4 | { 5 | public interface ILoginService 6 | { 7 | Task PerformTumblrLogin(string login, string password); 8 | 9 | bool CheckIfLoggedIn(); 10 | 11 | Task GetTumblrUsername(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/IMixtapeParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using TumblThree.Domain.Models; 3 | 4 | namespace TumblThree.Applications.Crawler 5 | { 6 | public interface IMixtapeParser 7 | { 8 | Regex GetMixtapeUrlRegex(); 9 | 10 | string CreateMixtapeUrl(string mixtapeId, string detectedUrl, MixtapeTypes mixtapeType); 11 | } 12 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Downloader/ICrawlerDataDownloader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TumblThree.Applications.Downloader 8 | { 9 | public interface ICrawlerDataDownloader 10 | { 11 | Task DownloadCrawlerDataAsync(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Crawler/ITumblrBlogDetector.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace TumblThree.Applications.Crawler 4 | { 5 | interface ITumblrBlogDetector 6 | { 7 | Task IsHiddenTumblrBlog(string url); 8 | 9 | Task IsPasswordProtectedTumblrBlog(string url); 10 | 11 | Task IsTumblrBlog(string url); 12 | } 13 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/IManagerView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Waf.Applications; 4 | using System.Windows; 5 | 6 | namespace TumblThree.Applications.Views 7 | { 8 | public interface IManagerView : IView 9 | { 10 | Dictionary> DataGridColumnRestore { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/IView.cs: -------------------------------------------------------------------------------- 1 | namespace System.Waf.Applications 2 | { 3 | /// 4 | /// Represents a view 5 | /// 6 | public interface IView 7 | { 8 | /// 9 | /// Gets or sets the data context of the view. 10 | /// 11 | object DataContext { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/IAuthenticateView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Waf.Applications; 3 | 4 | namespace TumblThree.Applications.Views 5 | { 6 | public interface IAuthenticateView : IView 7 | { 8 | void ShowDialog(object owner); 9 | 10 | event EventHandler Closed; 11 | 12 | void AddUrl(string url); 13 | 14 | string GetUrl(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/IWebmshareParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | using TumblThree.Domain.Models; 4 | 5 | namespace TumblThree.Applications.Crawler 6 | { 7 | public interface IWebmshareParser 8 | { 9 | Regex GetWebmshareUrlRegex(); 10 | 11 | string CreateWebmshareUrl(string webshareId, string detectedUrl, WebmshareTypes webmshareType); 12 | } 13 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ApplicationBusyContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TumblThree.Applications.Services 4 | { 5 | internal class ApplicationBusyContext : IDisposable 6 | { 7 | public Action DisposeCallback { get; set; } 8 | 9 | public void Dispose() 10 | { 11 | DisposeCallback(this); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Downloader/IDownloader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | using TumblThree.Applications.DataModels; 5 | 6 | namespace TumblThree.Applications.Downloader 7 | { 8 | public interface IDownloader 9 | { 10 | Task DownloadBlogAsync(); 11 | 12 | void UpdateProgressQueueInformation(string format, params object[] args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Properties/ManagerSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace TumblThree.Applications.Properties 4 | { 5 | [DataContract] 6 | public sealed class ManagerSettings : IExtensibleDataObject 7 | { 8 | public ManagerSettings() 9 | { 10 | } 11 | 12 | ExtensionDataObject IExtensibleDataObject.ExtensionData { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Properties/CodeAnalysisDictionary.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | waf 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Properties/CodeAnalysisDictionary.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | waf 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Properties/CodeAnalysisDictionary.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | waf 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Files/TumblrBlogFiles.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | 4 | namespace TumblThree.Domain.Models 5 | { 6 | [DataContract] 7 | public class TumblrBlogFiles : Files 8 | { 9 | public TumblrBlogFiles(string name, string location) : base(name, location) 10 | { 11 | BlogType = BlogTypes.tumblr; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/CrawlerServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.Services 2 | { 3 | public static class CrawlerServiceExtensions 4 | { 5 | public static void Crawl(this ICrawlerService crawlerService) 6 | { 7 | if (crawlerService.IsCrawl) 8 | { 9 | crawlerService.CrawlCommand.Execute(null); 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/ViewModels/IDetailsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Waf.Applications; 2 | using System.Windows.Input; 3 | using System.Windows.Media; 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Views 7 | { 8 | public interface IDetailsViewModel 9 | { 10 | IBlog BlogFile { get; set; } 11 | 12 | int Count { get; set; } 13 | 14 | object View { get; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IApplicationUpdateService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace TumblThree.Applications.Services 5 | { 6 | public interface IApplicationUpdateService 7 | { 8 | Task GetLatestReleaseFromServer(); 9 | 10 | bool IsNewVersionAvailable(); 11 | 12 | string GetNewAvailableVersion(); 13 | 14 | Uri GetDownloadUri(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ISelectionService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using TumblThree.Domain.Models; 4 | 5 | namespace TumblThree.Applications.Services 6 | { 7 | public interface ISelectionService 8 | { 9 | IList SelectedBlogFiles { get; } 10 | 11 | void AddRange(IEnumerable collection); 12 | 13 | void RemoveRange(IEnumerable collection); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ISharedCookieService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace TumblThree.Applications.Services 5 | { 6 | public interface ISharedCookieService 7 | { 8 | void GetUriCookie(CookieContainer request, Uri uri); 9 | 10 | void SetUriCookie(CookieCollection cookies); 11 | 12 | void Serialize(string path); 13 | 14 | void Deserialize(string path); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Files/TumblrHiddenBlogFiles.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | 4 | namespace TumblThree.Domain.Models 5 | { 6 | [DataContract] 7 | public class TumblrHiddenBlogFiles : Files 8 | { 9 | public TumblrHiddenBlogFiles(string name, string location) : base(name, location) 10 | { 11 | BlogType = BlogTypes.tmblrpriv; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Files/TumblrLikedByBlogFiles.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | 4 | namespace TumblThree.Domain.Models 5 | { 6 | [DataContract] 7 | public class TumblrLikedByBlogFiles : Files 8 | { 9 | public TumblrLikedByBlogFiles(string name, string location) : base(name, location) 10 | { 11 | BlogType = BlogTypes.tlb; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Files/TumblrSearchBlogFiles.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | 4 | namespace TumblThree.Domain.Models 5 | { 6 | [DataContract] 7 | public class TumblrSearchBlogFiles : Files 8 | { 9 | public TumblrSearchBlogFiles(string name, string location) : base(name, location) 10 | { 11 | BlogType = BlogTypes.tumblrsearch; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/IUrlValidator.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Domain.Models 2 | { 3 | public interface IUrlValidator 4 | { 5 | bool IsValidTumblrHiddenUrl(string url); 6 | bool IsValidTumblrLikedByUrl(string url); 7 | bool IsValidTumblrSearchUrl(string url); 8 | bool IsValidTumblrTagSearchUrl(string url); 9 | bool IsValidTumblrUrl(string url); 10 | string AddHttpsProtocol(string url); 11 | } 12 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Files/TumblrTagSearchBlogFiles.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | 4 | namespace TumblThree.Domain.Models 5 | { 6 | [DataContract] 7 | public class TumblrTagSearchBlogFiles : Files 8 | { 9 | public TumblrTagSearchBlogFiles(string name, string location) : base(name, location) 10 | { 11 | BlogType = BlogTypes.tumblrtagsearch; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/IGfycatParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using System.Threading.Tasks; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Crawler 7 | { 8 | public interface IGfycatParser 9 | { 10 | Regex GetGfycatUrlRegex(); 11 | 12 | Task RequestGfycatCajax(string gfyId); 13 | 14 | string ParseGfycatCajaxResponse(string result, GfycatTypes gfycatType); 15 | } 16 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Services/ClipboardService.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.Windows; 3 | 4 | using TumblThree.Applications.Services; 5 | 6 | namespace TumblThree.Presentation.Services 7 | { 8 | [Export(typeof(IClipboardService))] 9 | internal class ClipboardService : IClipboardService 10 | { 11 | public void SetText(string text) 12 | { 13 | Clipboard.SetText(text); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Crawler/ICrawler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | using TumblThree.Applications.DataModels; 5 | 6 | namespace TumblThree.Applications.Crawler 7 | { 8 | public interface ICrawler 9 | { 10 | Task Crawl(); 11 | 12 | Task IsBlogOnlineAsync(); 13 | 14 | Task UpdateMetaInformationAsync(); 15 | 16 | void UpdateProgressQueueInformation(string format, params object[] args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/IImgurParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using System.Threading.Tasks; 3 | 4 | namespace TumblThree.Applications.Crawler 5 | { 6 | public interface IImgurParser 7 | { 8 | Regex GetImgurImageRegex(); 9 | 10 | Regex GetImgurAlbumRegex(); 11 | 12 | Regex GetImgurAlbumHashRegex(); 13 | 14 | Regex GetImgurAlbumExtRegex(); 15 | 16 | Task RequestImgurAlbumSite(string gfyId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/ITumblrToText.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.Parser 2 | { 3 | public interface ITumblrToTextParser 4 | { 5 | string ParseAnswer(T post); 6 | string ParseAudioMeta(T post); 7 | string ParseConversation(T post); 8 | string ParseLink(T post); 9 | string ParsePhotoMeta(T post); 10 | string ParseQuote(T post); 11 | string ParseText(T post); 12 | string ParseVideoMeta(T post); 13 | } 14 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IFolderBrowserDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | 4 | namespace TumblThree.Applications.Services 5 | { 6 | public interface IFolderBrowserDialog 7 | { 8 | string Description { get; set; } 9 | Environment.SpecialFolder RootFolder { get; set; } 10 | string SelectedPath { get; set; } 11 | bool ShowNewFolderButton { get; set; } 12 | bool? ShowDialog(); 13 | bool? ShowDialog(Window owner); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ShellServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace TumblThree.Applications.Services 5 | { 6 | public static class ShellServiceExtensions 7 | { 8 | public static void ShowError(this IShellService shellService, Exception exception, string format, params object[] args) 9 | { 10 | shellService.ShowError(exception, string.Format(CultureInfo.CurrentCulture, format, args)); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/MetadataType.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using TumblThree.Domain.Attributes; 4 | using TumblThree.Domain.Converter; 5 | using TumblThree.Domain.Properties; 6 | 7 | namespace TumblThree.Domain.Models 8 | { 9 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 10 | public enum MetadataType 11 | { 12 | [LocalizedDescription("text", typeof(Resources))] 13 | Text, 14 | [LocalizedDescription("json", typeof(Resources))] 15 | Json 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/ConverterHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TumblThree.Presentation.Converters 4 | { 5 | internal static class ConverterHelper 6 | { 7 | public static bool IsParameterSet(string expectedParameter, object actualParameter) 8 | { 9 | var parameter = actualParameter as string; 10 | return !string.IsNullOrEmpty(parameter) && 11 | string.Equals(parameter, expectedParameter, StringComparison.OrdinalIgnoreCase); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/UguuTypes.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using TumblThree.Domain.Attributes; 4 | using TumblThree.Domain.Converter; 5 | using TumblThree.Domain.Properties; 6 | 7 | namespace TumblThree.Domain.Models 8 | { 9 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 10 | public enum UguuTypes 11 | { 12 | [LocalizedDescription("any", typeof(Resources))] 13 | Any, 14 | [LocalizedDescription("mp4", typeof(Resources))] 15 | Mp4, 16 | [LocalizedDescription("webm", typeof(Resources))] 17 | Webm 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/CatboxTypes.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using TumblThree.Domain.Attributes; 4 | using TumblThree.Domain.Converter; 5 | using TumblThree.Domain.Properties; 6 | 7 | namespace TumblThree.Domain.Models 8 | { 9 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 10 | public enum CatBoxTypes 11 | { 12 | [LocalizedDescription("any", typeof(Resources))] 13 | Any, 14 | [LocalizedDescription("mp4", typeof(Resources))] 15 | Mp4, 16 | [LocalizedDescription("webm", typeof(Resources))] 17 | Webm 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Files/IFiles.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | 4 | namespace TumblThree.Domain.Models 5 | { 6 | public interface IFiles : INotifyPropertyChanged 7 | { 8 | string Name { get; } 9 | 10 | BlogTypes BlogType { get; } 11 | 12 | IList Links { get; } 13 | 14 | void AddFileToDb(string fileName); 15 | 16 | bool CheckIfFileExistsInDB(string url); 17 | 18 | bool Save(); 19 | 20 | IFiles Load(string fileLocation); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/LoliSafeTypes.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using TumblThree.Domain.Attributes; 4 | using TumblThree.Domain.Converter; 5 | using TumblThree.Domain.Properties; 6 | 7 | namespace TumblThree.Domain.Models 8 | { 9 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 10 | public enum LoliSafeTypes 11 | { 12 | [LocalizedDescription("any", typeof(Resources))] 13 | Any, 14 | [LocalizedDescription("mp4", typeof(Resources))] 15 | Mp4, 16 | [LocalizedDescription("webm", typeof(Resources))] 17 | Webm 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/SafeMoeTypes.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using TumblThree.Domain.Attributes; 4 | using TumblThree.Domain.Converter; 5 | using TumblThree.Domain.Properties; 6 | 7 | namespace TumblThree.Domain.Models 8 | { 9 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 10 | public enum SafeMoeTypes 11 | { 12 | [LocalizedDescription("any", typeof(Resources))] 13 | Any, 14 | [LocalizedDescription("mp4", typeof(Resources))] 15 | Mp4, 16 | [LocalizedDescription("webm", typeof(Resources))] 17 | Webm 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrCrawlerData/TumblrCrawlerData.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.DataModels.TumblrApiJson; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrCrawlerData 4 | { 5 | public class TumblrCrawlerData : ITumblrCrawlerData 6 | { 7 | public T Data { get; protected set; } 8 | 9 | public string Filename { get; protected set; } 10 | 11 | public TumblrCrawlerData(string filename, T data) 12 | { 13 | this.Filename = filename; 14 | this.Data = data; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DesignData/SampleAboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.ViewModels; 2 | using TumblThree.Applications.Views; 3 | 4 | namespace TumblThree.Presentation.DesignData 5 | { 6 | public class SampleAboutViewModel : AboutViewModel 7 | { 8 | public SampleAboutViewModel() : base(new MockAboutView(), null) 9 | { 10 | } 11 | 12 | private class MockAboutView : MockView, IAboutView 13 | { 14 | public void ShowDialog(object owner) 15 | { 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/TumblrParser.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace TumblThree.Applications.Crawler 4 | { 5 | public class TumblrParser : ITumblrParser 6 | { 7 | public Regex GetTumblrPhotoUrlRegex() 8 | { 9 | return new Regex("\"(http[A-Za-z0-9_/:.]*media.tumblr.com[A-Za-z0-9_/:.]*(jpg|png|gif))\""); 10 | } 11 | 12 | public Regex GetTumblrVideoUrlRegex() 13 | { 14 | return new Regex("\"(http[A-Za-z0-9_/:.]*.com/video_file/[A-Za-z0-9_/:.]*)\""); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/ITumblrApiXmlToText.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | namespace TumblThree.Applications.Parser 4 | { 5 | public interface ITumblrApiXmlToTextParser 6 | { 7 | string ParseAnswer(XElement post); 8 | string ParseAudioMeta(XElement post); 9 | string ParseConversation(XElement post); 10 | string ParseLink(XElement post); 11 | string ParsePhotoMeta(XElement post); 12 | string ParseQuote(XElement post); 13 | string ParseText(XElement post); 14 | string ParseVideoMeta(XElement post); 15 | } 16 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/MixtapeTypes.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using TumblThree.Domain.Attributes; 4 | using TumblThree.Domain.Converter; 5 | using TumblThree.Domain.Properties; 6 | 7 | namespace TumblThree.Domain.Models 8 | { 9 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 10 | public enum MixtapeTypes 11 | { 12 | [LocalizedDescription("any", typeof(Resources))] 13 | Any, 14 | [LocalizedDescription("mp4", typeof(Resources))] 15 | Mp4, 16 | [LocalizedDescription("webm", typeof(Resources))] 17 | Webm 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/WebmshareTypes.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using TumblThree.Domain.Attributes; 4 | using TumblThree.Domain.Converter; 5 | using TumblThree.Domain.Properties; 6 | 7 | namespace TumblThree.Domain.Models 8 | { 9 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 10 | public enum WebmshareTypes 11 | { 12 | [LocalizedDescription("any", typeof(Resources))] 13 | Any, 14 | [LocalizedDescription("mp4", typeof(Resources))] 15 | Mp4, 16 | [LocalizedDescription("webm", typeof(Resources))] 17 | Webm 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Crawler/ICrawlerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | using TumblThree.Applications.DataModels; 5 | using TumblThree.Applications.Services; 6 | using TumblThree.Domain.Models; 7 | 8 | namespace TumblThree.Applications.Crawler 9 | { 10 | public interface ICrawlerFactory 11 | { 12 | ICrawler GetCrawler(IBlog blog); 13 | 14 | ICrawler GetCrawler(IBlog blog, CancellationToken ct, PauseToken pt, IProgress progress, IShellService shellService, ICrawlerService crawlerService, IManagerService managerService); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IBlogService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TumblThree.Applications.Services 4 | { 5 | public interface IBlogService 6 | { 7 | void UpdateBlogProgress(); 8 | 9 | void UpdateBlogPostCount(string propertyName); 10 | 11 | void UpdateBlogDB(string fileName); 12 | 13 | bool CreateDataFolder(); 14 | 15 | bool CheckIfFileExistsInDB(string url); 16 | 17 | bool CheckIfBlogShouldCheckDirectory(string url); 18 | 19 | bool CheckIfFileExistsInDirectory(string url); 20 | 21 | void SaveFiles(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/LinkPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class LinkPost : TumblrPost 6 | { 7 | public LinkPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Text; 10 | DbType = "DownloadedLinks"; 11 | TextFileLocation = Resources.FileNameLinks; 12 | } 13 | 14 | public LinkPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/TextPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class TextPost : TumblrPost 6 | { 7 | public TextPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Text; 10 | DbType = "DownloadedTexts"; 11 | TextFileLocation = Resources.FileNameTexts; 12 | } 13 | 14 | public TextPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IManagerService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Services 7 | { 8 | public interface IManagerService 9 | { 10 | ObservableCollection BlogFiles { get; } 11 | 12 | IEnumerable Databases { get; } 13 | 14 | bool CheckIfFileExistsInDB(string url); 15 | 16 | void RemoveDatabase(IFiles database); 17 | 18 | void AddDatabase(IFiles database); 19 | 20 | void ClearDatabases(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/AudioPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class AudioPost : TumblrPost 6 | { 7 | public AudioPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Binary; 10 | DbType = "DownloadedAudios"; 11 | TextFileLocation = Resources.FileNameAudios; 12 | } 13 | 14 | public AudioPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/PhotoPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class PhotoPost : TumblrPost 6 | { 7 | public PhotoPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Binary; 10 | DbType = "DownloadedPhotos"; 11 | TextFileLocation = Resources.FileNamePhotos; 12 | } 13 | 14 | public PhotoPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/QuotePost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class QuotePost : TumblrPost 6 | { 7 | public QuotePost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Text; 10 | DbType = "DownloadedQuotes"; 11 | TextFileLocation = Resources.FileNameQuotes; 12 | } 13 | 14 | public QuotePost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/VideoPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class VideoPost : TumblrPost 6 | { 7 | public VideoPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Binary; 10 | DbType = "DownloadedVideos"; 11 | TextFileLocation = Resources.FileNameVideos; 12 | } 13 | 14 | public VideoPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/AnswerPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class AnswerPost : TumblrPost 6 | { 7 | public AnswerPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Text; 10 | DbType = "DownloadedAnswers"; 11 | TextFileLocation = Resources.FileNameAnswers; 12 | } 13 | 14 | public AnswerPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Queue/QueueListItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Waf.Foundation; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Domain.Queue 7 | { 8 | [Serializable] 9 | public class QueueListItem : Model 10 | { 11 | private string progress; 12 | 13 | public QueueListItem(IBlog blog) 14 | { 15 | Blog = blog; 16 | } 17 | 18 | public IBlog Blog { get; } 19 | 20 | public string Progress 21 | { 22 | get { return progress; } 23 | set { SetProperty(ref progress, value); } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/LayoutResources.xaml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 5 | 6 | 11 7 | 8 | 4 9 | 10 | 9 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/AudioMetaPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class AudioMetaPost : TumblrPost 6 | { 7 | public AudioMetaPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Text; 10 | DbType = "DownloadedAudioMetas"; 11 | TextFileLocation = Resources.FileNameMetaAudio; 12 | } 13 | 14 | public AudioMetaPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/PhotoMetaPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class PhotoMetaPost : TumblrPost 6 | { 7 | public PhotoMetaPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Text; 10 | DbType = "DownloadedPhotoMetas"; 11 | TextFileLocation = Resources.FileNameMetaPhoto; 12 | } 13 | 14 | public PhotoMetaPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/VideoMetaPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class VideoMetaPost : TumblrPost 6 | { 7 | public VideoMetaPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Text; 10 | DbType = "DownloadedVideoMetas"; 11 | TextFileLocation = Resources.FileNameMetaVideo; 12 | } 13 | 14 | public VideoMetaPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/ExternalPhotoPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class ExternalPhotoPost : TumblrPost 6 | { 7 | public ExternalPhotoPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Binary; 10 | DbType = "DownloadedPhotos"; 11 | TextFileLocation = Resources.FileNamePhotos; 12 | } 13 | 14 | public ExternalPhotoPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/ExternalVideoPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class ExternalVideoPost : TumblrPost 6 | { 7 | public ExternalVideoPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Binary; 10 | DbType = "DownloadedVideos"; 11 | TextFileLocation = Resources.FileNameVideos; 12 | } 13 | 14 | public ExternalVideoPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/ConversationPost.cs: -------------------------------------------------------------------------------- 1 | using TumblThree.Applications.Properties; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrPosts 4 | { 5 | public class ConversationPost : TumblrPost 6 | { 7 | public ConversationPost(string url, string id, string date) : base(url, id, date) 8 | { 9 | PostType = PostType.Text; 10 | DbType = "DownloadedConversations"; 11 | TextFileLocation = Resources.FileNameConversations; 12 | } 13 | 14 | public ConversationPost(string url, string id) : this(url, id, string.Empty) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/ViewModels/FullScreenMediaViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | 3 | using System.Waf.Applications; 4 | 5 | using TumblThree.Applications.Views; 6 | 7 | 8 | namespace TumblThree.Applications.ViewModels 9 | { 10 | [Export] 11 | public class FullScreenMediaViewModel : ViewModel 12 | { 13 | [ImportingConstructor] 14 | public FullScreenMediaViewModel(IFullScreenMediaView view) 15 | : base(view) 16 | { 17 | } 18 | 19 | public void ShowDialog(object owner) 20 | { 21 | ViewCore.ShowDialog(owner); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/TumblThree/SharedAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Runtime.InteropServices; 5 | 6 | [assembly: AssemblyCompany("")] 7 | [assembly: AssemblyProduct("TumblThree")] 8 | [assembly: AssemblyCopyright("Copyright (C) 2016-2018 Johannes Meyer zum Alten Borgloh")] 9 | [assembly: AssemblyTrademark("")] 10 | [assembly: AssemblyCulture("")] 11 | [assembly: CLSCompliant(false)] // The WinRT API is not CLS-compliant (e.g. usage of uint) 12 | 13 | [assembly: ComVisible(false)] 14 | [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)] 15 | [assembly: AssemblyVersion("1.0.8.52")] 16 | [assembly: AssemblyFileVersion("1.0.8.52")] 17 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Services/PresentationService.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Markup; 5 | 6 | using TumblThree.Applications.Services; 7 | 8 | namespace TumblThree.Presentation.Services 9 | { 10 | [Export(typeof(IPresentationService))] 11 | internal class PresentationService : IPresentationService 12 | { 13 | public void Initialize() 14 | { 15 | FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata( 16 | XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IPresentationService.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.Services 2 | { 3 | /// 4 | /// Service for initializing the presentation layer. These services are called before any ModuleController is 5 | /// initialized. 6 | /// 7 | /// 8 | /// This service can be used to initialize the culture settings (must be done before the first view is created) 9 | /// or to register resource dictionaries. 10 | /// 11 | public interface IPresentationService 12 | { 13 | /// 14 | /// Initializes the service. 15 | /// 16 | void Initialize(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/DateToDisplayValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace TumblThree.Presentation.Converters 6 | { 7 | public class DateToDisplayValueConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | var date = (DateTime)value; 12 | return date != DateTime.MinValue ? (object)date : ""; 13 | } 14 | 15 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrPosts/TumblrPost.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Applications.DataModels 2 | { 3 | public enum PostType { Binary, Text } 4 | 5 | public abstract class TumblrPost 6 | { 7 | public PostType PostType { get; protected set; } 8 | 9 | public string Url { get; } 10 | 11 | public string Id { get; } 12 | 13 | public string Date { get; } 14 | 15 | public string DbType { get; protected set; } 16 | 17 | public string TextFileLocation { get; protected set; } 18 | 19 | public TumblrPost(string url, string id, string date) 20 | { 21 | this.Url = url; 22 | this.Id = id; 23 | this.Date = date; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/ViewModels/CrawlerViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.Waf.Applications; 3 | 4 | using TumblThree.Applications.Services; 5 | using TumblThree.Applications.Views; 6 | 7 | namespace TumblThree.Applications.ViewModels 8 | { 9 | [Export] 10 | public class CrawlerViewModel : ViewModel 11 | { 12 | [ImportingConstructor] 13 | public CrawlerViewModel(ICrawlerView view, IShellService shellService, ICrawlerService crawlerService) : base(view) 14 | { 15 | CrawlerService = crawlerService; 16 | ShellService = shellService; 17 | } 18 | 19 | public IShellService ShellService { get; } 20 | 21 | public ICrawlerService CrawlerService { get; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Views/IShellView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Waf.Applications; 4 | 5 | namespace TumblThree.Applications.Views 6 | { 7 | public interface IShellView : IView 8 | { 9 | double VirtualScreenWidth { get; } 10 | 11 | double VirtualScreenHeight { get; } 12 | 13 | double Left { get; set; } 14 | 15 | double Top { get; set; } 16 | 17 | double Width { get; set; } 18 | 19 | double Height { get; set; } 20 | 21 | bool IsMaximized { get; set; } 22 | 23 | double GridSplitterPosition { get; set; } 24 | 25 | event CancelEventHandler Closing; 26 | 27 | event EventHandler Closed; 28 | 29 | void Show(); 30 | 31 | void Close(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Foundation/IReadOnlyObservableList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Specialized; 3 | 4 | namespace System.Waf.Foundation 5 | { 6 | /// 7 | /// Represents a read-only list of elements that can be accessed by index. Additional the list 8 | /// notifies listeners of changes, such as when items get added and removed. 9 | /// 10 | /// 11 | /// The type of elements in the read-only list. This type parameter is covariant. 12 | /// That is, you can use either the type you specified or any type that is more 13 | /// derived. 14 | /// 15 | public interface IReadOnlyObservableList : IReadOnlyList, INotifyCollectionChanged 16 | { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/IModuleController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace System.Waf.Applications 7 | { 8 | /// 9 | /// Interface for a module controller which is responsible for the module lifecycle. 10 | /// 11 | public interface IModuleController 12 | { 13 | /// 14 | /// Initializes the module controller. 15 | /// 16 | void Initialize(); 17 | 18 | /// 19 | /// Run the module controller. 20 | /// 21 | void Run(); 22 | 23 | /// 24 | /// Shutdown the module controller. 25 | /// 26 | void Shutdown(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/TotalImageConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | using TumblThree.Presentation.Properties; 6 | 7 | namespace TumblThree.Presentation.Converters 8 | { 9 | public class TotalImageConverter : IMultiValueConverter 10 | { 11 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 12 | { 13 | object totalImageCount = values[0]; 14 | return string.Format(CultureInfo.CurrentCulture, Resources.NumberOfImages, totalImageCount); 15 | } 16 | 17 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 18 | { 19 | throw new NotSupportedException(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/IntToDisplayValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace TumblThree.Presentation.Converters 6 | { 7 | public class IntToDisplayValueConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | var number = (int)value; 12 | return number != 0 ? (object)number : ""; 13 | } 14 | 15 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 16 | { 17 | var displayValue = value as string; 18 | return string.IsNullOrEmpty(displayValue) ? 0 : int.Parse(displayValue, CultureInfo.CurrentCulture); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Runtime.InteropServices; 4 | using System.Runtime.CompilerServices; 5 | using System.Windows.Markup; 6 | 7 | 8 | [assembly: AssemblyTitle("WPF Application Framework (WAF)")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyProduct("WPF Application Framework (WAF)")] 12 | 13 | 14 | [assembly: Guid("331cc379-bc8e-4129-8b6a-5698bf93b774")] 15 | 16 | 17 | [assembly: XmlnsDefinition("http://waf.codeplex.com/schemas", "System.Waf.Presentation")] 18 | [assembly: XmlnsDefinition("http://waf.codeplex.com/schemas", "System.Waf.Presentation.Converters")] 19 | 20 | 21 | #if (!STRONG_NAME) 22 | [assembly: InternalsVisibleTo("WpfApplicationFramework.Test")] 23 | #endif -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Extensions/TaskTimeoutExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace TumblThree.Applications.Extensions 5 | { 6 | static class TaskTimeoutExtension 7 | { 8 | public async static Task TimeoutAfter(this Task task, int delay) 9 | { 10 | await Task.WhenAny(task, Task.Delay(delay * 1000)); 11 | 12 | if (!task.IsCompleted) 13 | throw new TimeoutException(); 14 | 15 | return await task; 16 | } 17 | 18 | public async static Task TimeoutAfter(this Task task, int delay) 19 | { 20 | await Task.WhenAny(task, Task.Delay(delay * 1000)); 21 | 22 | if (!task.IsCompleted) 23 | throw new TimeoutException(); 24 | 25 | await task; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/ValidationRules/TimeSpanRule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Controls; 4 | 5 | using TumblThree.Presentation.Properties; 6 | 7 | namespace TumblThree.Presentation.ValidationRules 8 | { 9 | public class TimeSpanRule : ValidationRule 10 | { 11 | public override ValidationResult Validate(object value, CultureInfo cultureInfo) 12 | { 13 | if (((string)value).Length > 7) 14 | { 15 | TimeSpan temp; 16 | if (TimeSpan.TryParse((string)value, out temp)) 17 | { 18 | return new ValidationResult(true, null); 19 | } 20 | } 21 | return new ValidationResult(false, string.Format(CultureInfo.CurrentCulture, Resources.TimeSpanTypeError)); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/PostQueue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.Generic; 3 | 4 | namespace TumblThree.Applications.DataModels 5 | { 6 | public class PostQueue : IPostQueue 7 | { 8 | private BlockingCollection postQueue; 9 | 10 | public PostQueue(IProducerConsumerCollection postTaskCollection) 11 | { 12 | postQueue = new BlockingCollection(postTaskCollection); 13 | } 14 | 15 | public void Add(T post) 16 | { 17 | postQueue.Add(post); 18 | } 19 | 20 | public void CompleteAdding() 21 | { 22 | postQueue.CompleteAdding(); 23 | } 24 | 25 | public IEnumerable GetConsumingEnumerable() 26 | { 27 | return postQueue.GetConsumingEnumerable(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/DataModels/TumblrSearchJson.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TumblThree.Applications.DataModels.TumblrSearchJson 4 | { 5 | public class TumblrSearchJson 6 | { 7 | public Meta meta { get; set; } 8 | public Response response { get; set; } 9 | } 10 | 11 | public class Meta 12 | { 13 | public int status { get; set; } 14 | public string msg { get; set; } 15 | } 16 | 17 | public class Response 18 | { 19 | public string posts_html { get; set; } 20 | public object blogs_html { get; set; } 21 | public string tracking_html { get; set; } 22 | public List related_searches { get; set; } 23 | public bool show_psa { get; set; } 24 | public bool tracked_tag { get; set; } 25 | public List yahoo_view_data { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/BlogTitleConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Waf.Foundation; 5 | using System.Windows.Data; 6 | 7 | using TumblThree.Domain.Queue; 8 | 9 | namespace TumblThree.Presentation.Converters 10 | { 11 | public class BlogTitleConverter : IMultiValueConverter 12 | { 13 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | var crawlingQueuelistItem = (ReadOnlyObservableList)values[0]; 16 | 17 | return string.Join(" - ", crawlingQueuelistItem.Select(x => x.Blog.Name).ToArray()); 18 | } 19 | 20 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 21 | { 22 | throw new NotSupportedException(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/UguuParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Parser 7 | { 8 | public class UguuParser : IUguuParser 9 | { 10 | public Regex GetUguuUrlRegex() 11 | { 12 | return new Regex("(http[A-Za-z0-9_/:.]*a.uguu.se/(.*))"); 13 | } 14 | 15 | public string CreateUguuUrl(string uguuId, string detectedUrl, UguuTypes uguuType) 16 | { 17 | string url; 18 | switch ( uguuType) 19 | { 20 | case UguuTypes.Mp4: 21 | url = @"https://a.uguu.se/" + uguuId + ".mp4"; 22 | break; 23 | case UguuTypes.Webm: 24 | url = @"https://a.uguu.se/" + uguuId + ".webm"; 25 | break; 26 | case UguuTypes.Any: 27 | url = detectedUrl; 28 | break; 29 | default: 30 | throw new ArgumentOutOfRangeException(); 31 | } 32 | return url; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/CrawlerView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | 5 | using TumblThree.Applications.ViewModels; 6 | using TumblThree.Applications.Views; 7 | 8 | namespace TumblThree.Presentation.Views 9 | { 10 | /// 11 | /// Interaction logic for CrawlerView.xaml 12 | /// 13 | [Export(typeof(ICrawlerView))] 14 | public partial class CrawlerView : ICrawlerView 15 | { 16 | private readonly Lazy viewModel; 17 | 18 | public CrawlerView() 19 | { 20 | InitializeComponent(); 21 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 22 | } 23 | 24 | private CrawlerViewModel ViewModel 25 | { 26 | get { return viewModel.Value; } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/SafeMoeParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Parser 7 | { 8 | public class SafeMoeParser : ISafeMoeParser 9 | { 10 | public Regex GetSafeMoeUrlRegex() 11 | { 12 | return new Regex("(http[A-Za-z0-9_/:.]*a.safe.moe/(.*))"); 13 | } 14 | 15 | public string CreateSafeMoeUrl(string id, string detectedUrl, SafeMoeTypes type) 16 | { 17 | string url; 18 | switch ( type) 19 | { 20 | case SafeMoeTypes.Mp4: 21 | url = @"https://a.safe.moe/" + id + ".mp4"; 22 | break; 23 | case SafeMoeTypes.Webm: 24 | url = @"https://a.safe.moe/" + id + ".webm"; 25 | break; 26 | case SafeMoeTypes.Any: 27 | url = detectedUrl; 28 | break; 29 | default: 30 | throw new ArgumentOutOfRangeException(); 31 | } 32 | return url; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/CatBoxParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Parser 7 | { 8 | public class CatBoxParser : ICatBoxParser 9 | { 10 | public Regex GetCatBoxUrlRegex() 11 | { 12 | return new Regex("(http[A-Za-z0-9_/:.]*files.catbox.moe/(.*))"); 13 | } 14 | 15 | public string CreateCatBoxUrl(string id, string detectedUrl, CatBoxTypes type) 16 | { 17 | string url; 18 | switch ( type) 19 | { 20 | case CatBoxTypes.Mp4: 21 | url = @"https://files.catbox.moe/" + id + ".mp4"; 22 | break; 23 | case CatBoxTypes.Webm: 24 | url = @"https://files.catbox.moe/" + id + ".webm"; 25 | break; 26 | case CatBoxTypes.Any: 27 | url = detectedUrl; 28 | break; 29 | default: 30 | throw new ArgumentOutOfRangeException(); 31 | } 32 | return url; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/LoliSafeParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Parser 7 | { 8 | public class LoliSafeParser : ILoliSafeParser 9 | { 10 | public Regex GetLoliSafeUrlRegex() 11 | { 12 | return new Regex("(http[A-Za-z0-9_/:.]*loli.temel.me/(.*))"); 13 | } 14 | 15 | public string CreateLoliSafeUrl(string id, string detectedUrl, LoliSafeTypes type) 16 | { 17 | string url; 18 | switch ( type) 19 | { 20 | case LoliSafeTypes.Mp4: 21 | url = @"https://loli.temel.me/" + id + ".mp4"; 22 | break; 23 | case LoliSafeTypes.Webm: 24 | url = @"https://loli.temel.me/" + id + ".webm"; 25 | break; 26 | case LoliSafeTypes.Any: 27 | url = detectedUrl; 28 | break; 29 | default: 30 | throw new ArgumentOutOfRangeException(); 31 | } 32 | return url; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Attributes/LocalizedDescriptionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Resources; 4 | 5 | 6 | namespace TumblThree.Domain.Attributes 7 | { 8 | public class LocalizedDescriptionAttribute : DescriptionAttribute 9 | { 10 | ResourceManager _resourceManager; 11 | string _resourceKey; 12 | 13 | public LocalizedDescriptionAttribute(string resourceKey, Type resourceType) 14 | { 15 | _resourceManager = new ResourceManager(resourceType); 16 | _resourceKey = resourceKey; 17 | } 18 | 19 | public override string Description 20 | { 21 | get 22 | { 23 | string description = _resourceManager.GetString(_resourceKey); 24 | return string.IsNullOrWhiteSpace(description) ? string.Format("[[{0}]]", _resourceKey) : description; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/NullToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace TumblThree.Presentation.Converters 7 | { 8 | public class NullToVisibilityConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | bool invert = ConverterHelper.IsParameterSet("invert", parameter); 13 | 14 | if (invert) 15 | { 16 | return value == null ? Visibility.Visible : Visibility.Collapsed; 17 | } 18 | return value != null ? Visibility.Visible : Visibility.Collapsed; 19 | } 20 | 21 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 22 | { 23 | throw new NotSupportedException(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DispatcherHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Permissions; 2 | using System.Windows.Threading; 3 | 4 | namespace TumblThree.Presentation 5 | { 6 | internal static class DispatcherHelper 7 | { 8 | /// 9 | /// Execute the event queue of the dispatcher. 10 | /// 11 | [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 12 | internal static void DoEvents() 13 | { 14 | var frame = new DispatcherFrame(); 15 | Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 16 | new DispatcherOperationCallback(ExitFrame), frame); 17 | Dispatcher.PushFrame(frame); 18 | } 19 | 20 | private static object ExitFrame(object frame) 21 | { 22 | ((DispatcherFrame)frame).Continue = false; 23 | return null; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/StatusToBoolConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | using TumblThree.Presentation.Properties; 6 | 7 | namespace TumblThree.Presentation.Converters 8 | { 9 | [ValueConversion(typeof(bool), typeof(bool))] 10 | public class StatusToBoolConverter : IValueConverter 11 | { 12 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 13 | { 14 | bool boolValue = value is bool && (bool)value; 15 | 16 | return boolValue 17 | ? string.Format(CultureInfo.CurrentCulture, Resources.Online) 18 | : string.Format(CultureInfo.CurrentCulture, Resources.Offline); 19 | } 20 | 21 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Data/SupportedFileTypes.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TumblThree.Applications.Data 4 | { 5 | internal static class SupportedFileTypes 6 | { 7 | private static readonly string[] blogFileExtensions = new string[] { ".tumblr", ".insta", ".twitter" }; 8 | private static readonly string[] queueFileExtensions = new string[] { ".que" }; 9 | private static readonly string[] bloglistExportFileType = new string[] { ".txt" }; 10 | 11 | public static IReadOnlyList BlogFileExtensions 12 | { 13 | get { return blogFileExtensions; } 14 | } 15 | 16 | public static IReadOnlyList QueueFileExtensions 17 | { 18 | get { return queueFileExtensions; } 19 | } 20 | 21 | public static IReadOnlyList BloglistExportFileType 22 | { 23 | get { return bloglistExportFileType; } 24 | } 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/ItemsCountConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | using TumblThree.Presentation.Properties; 6 | 7 | namespace TumblThree.Presentation.Converters 8 | { 9 | public class ItemsCountConverter : IValueConverter 10 | { 11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 12 | { 13 | var itemsCount = (int)value; 14 | if (itemsCount == 1) 15 | { 16 | return Resources.OneItem; 17 | } 18 | else 19 | { 20 | return string.Format(CultureInfo.CurrentCulture, Resources.NumberOfItems, itemsCount); 21 | } 22 | } 23 | 24 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 25 | { 26 | throw new NotSupportedException(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IWebRequestFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Net; 4 | using System.Threading.Tasks; 5 | 6 | namespace TumblThree.Applications.Crawler 7 | { 8 | public interface IWebRequestFactory 9 | { 10 | HttpWebRequest CreateGetReqeust(string url); 11 | 12 | HttpWebRequest CreateGetXhrReqeust(string url, string referer = "", Dictionary headers = null); 13 | 14 | HttpWebRequest CreatePostReqeust(string url, string referer = "", Dictionary headers = null); 15 | 16 | HttpWebRequest CreatePostXhrReqeust(string url, string referer = "", Dictionary headers = null); 17 | 18 | Task RemotePageIsValid(string url); 19 | 20 | Task ReadReqestToEnd(HttpWebRequest request); 21 | 22 | Stream GetStreamForApiRequest(Stream stream); 23 | 24 | string UrlEncode(IDictionary parameters); 25 | } 26 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/ValidationRules/IntRangeRule.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Controls; 3 | 4 | using TumblThree.Presentation.Properties; 5 | 6 | namespace TumblThree.Presentation.ValidationRules 7 | { 8 | public class IntRangeRule : ValidationRule 9 | { 10 | public override ValidationResult Validate(object value, CultureInfo cultureInfo) 11 | { 12 | try 13 | { 14 | var temp = 0; 15 | if (int.TryParse((string)value, out temp)) 16 | { 17 | return new ValidationResult(true, null); 18 | } 19 | } 20 | catch 21 | { 22 | return new ValidationResult(false, string.Format(CultureInfo.CurrentCulture, Resources.IntRangeError)); 23 | } 24 | return new ValidationResult(false, string.Format(CultureInfo.CurrentCulture, Resources.IntTypeError)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/BlogQueueProgressConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace TumblThree.Presentation.Converters 6 | { 7 | public class BlogQueueProgressConverter : IMultiValueConverter 8 | { 9 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | //if (values.First() == DependencyProperty.UnsetValue) { return DependencyProperty.UnsetValue; } 12 | 13 | //var downloadedImages = values[0]; 14 | //var totalImages = values[1]; 15 | 16 | //return string.Format(CultureInfo.CurrentCulture, Resources.DownloadedImagesOf, downloadedImages, totalImages); 17 | 18 | return values[0]; 19 | } 20 | 21 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 22 | { 23 | throw new NotSupportedException(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/IsLessThanConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Windows; 5 | using System.Windows.Data; 6 | 7 | namespace TumblThree.Presentation.Converters 8 | { 9 | public class IsLessThanConverter : IMultiValueConverter 10 | { 11 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 12 | { 13 | if (values.First() == DependencyProperty.UnsetValue) 14 | { 15 | return DependencyProperty.UnsetValue; 16 | } 17 | 18 | double value = System.Convert.ToDouble(values[0]); 19 | double threshold = System.Convert.ToDouble(values[1]); 20 | 21 | return threshold < value; 22 | } 23 | 24 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 25 | { 26 | throw new NotSupportedException(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/GfycatType.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using TumblThree.Domain.Attributes; 4 | using TumblThree.Domain.Converter; 5 | using TumblThree.Domain.Properties; 6 | 7 | namespace TumblThree.Domain.Models 8 | { 9 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 10 | public enum GfycatTypes 11 | { 12 | [LocalizedDescription("mp4", typeof(Resources))] 13 | Mp4, 14 | [LocalizedDescription("webm", typeof(Resources))] 15 | Webm, 16 | [LocalizedDescription("webp", typeof(Resources))] 17 | Webp, 18 | [LocalizedDescription("poster", typeof(Resources))] 19 | Poster, 20 | [LocalizedDescription("max5mbgif", typeof(Resources))] 21 | Max5mbGif, 22 | [LocalizedDescription("max2mbgif", typeof(Resources))] 23 | Max2mbGif, 24 | [LocalizedDescription("mjpg", typeof(Resources))] 25 | Mjpg, 26 | [LocalizedDescription("gif", typeof(Resources))] 27 | Gif 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/ValidationRules/BandwidthRangeRule.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Controls; 3 | 4 | using TumblThree.Presentation.Properties; 5 | 6 | namespace TumblThree.Presentation.ValidationRules 7 | { 8 | public class BandwidthRangeRule : ValidationRule 9 | { 10 | public override ValidationResult Validate(object value, CultureInfo cultureInfo) 11 | { 12 | try 13 | { 14 | long temp = long.Parse((string)value); 15 | 16 | if (temp >= 0 && temp <= (long.MaxValue / 1024)) 17 | { 18 | return new ValidationResult(true, null); 19 | } 20 | } 21 | catch 22 | { 23 | return new ValidationResult(false, string.Format(CultureInfo.CurrentCulture, Resources.IntTypeError)); 24 | } 25 | return new ValidationResult(false, string.Format(CultureInfo.CurrentCulture, Resources.BandwidthRangeError)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/IsQueueItemCrawlingMultiConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Waf.Foundation; 4 | using System.Windows.Data; 5 | 6 | using TumblThree.Domain.Queue; 7 | 8 | namespace TumblThree.Presentation.Converters 9 | { 10 | public class IsQueueItemCrawlingMultiConverter : IMultiValueConverter 11 | { 12 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 13 | { 14 | var crawlingQueuelistItem = (ReadOnlyObservableList)values[0]; 15 | var currentQueuelistItem = (QueueListItem)values[1]; 16 | 17 | if (crawlingQueuelistItem.Contains(currentQueuelistItem)) 18 | { 19 | return true; 20 | } 21 | 22 | return false; 23 | } 24 | 25 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 26 | { 27 | throw new NotSupportedException(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/RateLimiter/RateLimiter/LongMath.cs: -------------------------------------------------------------------------------- 1 | namespace Guava.RateLimiter 2 | { 3 | public static class LongMath 4 | { 5 | /// 6 | /// Returns the sum of 7 | /// and 8 | /// unless it would overflow or underflow in which case 9 | /// long.MaxValue or long.MaxValue is returned, respectively. 10 | /// 11 | /// since 20.0 12 | /// 13 | public static long SaturatedAdd(long a, long b) 14 | { 15 | var naiveSum = unchecked(a + b); 16 | if ((a ^ b) < 0 | (a ^ naiveSum) >= 0) 17 | { 18 | // If a and b have different signs or a has the same sign as the result then there was no 19 | // overflow, return. 20 | return naiveSum; 21 | } 22 | // we did over/under flow, if the sign is negative we should return MAX otherwise MIN 23 | return naiveSum < 0 ? long.MaxValue : long.MinValue; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Data/StringListConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | 6 | namespace TumblThree.Applications.Data 7 | { 8 | public static class StringListConverter 9 | { 10 | public static string ToString(IEnumerable list, string separator = null) 11 | { 12 | return string.Join(GetSeparator(separator), list ?? new string[0]); 13 | } 14 | 15 | public static IEnumerable FromString(string text, string separator = null) 16 | { 17 | return (text ?? "").Split(new[] { GetSeparator(separator).Trim(' ') }, StringSplitOptions.RemoveEmptyEntries) 18 | .Select(x => x.Trim(' ')).Where(x => !string.IsNullOrEmpty(x)).ToArray(); 19 | } 20 | 21 | private static string GetSeparator(string separator) 22 | { 23 | return !string.IsNullOrEmpty(separator) ? separator : CultureInfo.CurrentCulture.TextInfo.ListSeparator + " "; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/App.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/InverseBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Data; 3 | 4 | namespace TumblThree.Presentation.Converters 5 | { 6 | [ValueConversion(typeof(bool), typeof(bool))] 7 | public class InverseBooleanConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, 10 | System.Globalization.CultureInfo culture) 11 | { 12 | if (targetType != typeof(bool)) 13 | { 14 | throw new InvalidOperationException("The target must be a boolean"); 15 | } 16 | 17 | return !(bool)value; 18 | } 19 | 20 | public object ConvertBack(object value, Type targetType, object parameter, 21 | System.Globalization.CultureInfo culture) 22 | { 23 | if (targetType != typeof(bool)) 24 | { 25 | throw new InvalidOperationException("The target must be a boolean"); 26 | } 27 | 28 | return !(bool)value; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/DispatcherHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Security.Permissions; 6 | using System.Windows.Threading; 7 | 8 | namespace System.Waf.Applications 9 | { 10 | internal static class DispatcherHelper 11 | { 12 | /// 13 | /// Execute the event queue of the dispatcher. 14 | /// 15 | [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 16 | internal static void DoEvents() 17 | { 18 | DispatcherFrame frame = new DispatcherFrame(); 19 | Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 20 | new DispatcherOperationCallback(ExitFrame), frame); 21 | Dispatcher.PushFrame(frame); 22 | } 23 | 24 | private static object ExitFrame(object frame) 25 | { 26 | ((DispatcherFrame)frame).Continue = false; 27 | return null; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/BlogQueueInfoConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Windows; 5 | using System.Windows.Data; 6 | 7 | using TumblThree.Presentation.Properties; 8 | 9 | namespace TumblThree.Presentation.Converters 10 | { 11 | public class BlogQueueInfoConverter : IMultiValueConverter 12 | { 13 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | if (values.First() == DependencyProperty.UnsetValue) 16 | { 17 | return DependencyProperty.UnsetValue; 18 | } 19 | 20 | object downloadedImages = values[0]; 21 | object totalImages = values[1]; 22 | 23 | return string.Format(CultureInfo.CurrentCulture, Resources.DownloadedFilesOf, downloadedImages, totalImages); 24 | } 25 | 26 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 27 | { 28 | throw new NotSupportedException(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/AboutView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows; 5 | 6 | using TumblThree.Applications.ViewModels; 7 | using TumblThree.Applications.Views; 8 | 9 | namespace TumblThree.Presentation.Views 10 | { 11 | /// 12 | /// Interaction logic for AboutView.xaml 13 | /// 14 | [Export(typeof(IAboutView)), PartCreationPolicy(CreationPolicy.NonShared)] 15 | public partial class AboutView : Window, IAboutView 16 | { 17 | private readonly Lazy viewModel; 18 | 19 | public AboutView() 20 | { 21 | InitializeComponent(); 22 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 23 | } 24 | 25 | private AboutViewModel ViewModel 26 | { 27 | get { return viewModel.Value; } 28 | } 29 | 30 | public void ShowDialog(object owner) 31 | { 32 | Owner = owner as Window; 33 | ShowDialog(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Themes/Generic/SuperToolTip.xaml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2018 Johannes Meyer zum Alten Borgloh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/IsBlogInQueueMultiConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Waf.Foundation; 5 | using System.Windows.Data; 6 | 7 | using TumblThree.Domain.Models; 8 | using TumblThree.Domain.Queue; 9 | 10 | namespace TumblThree.Presentation.Converters 11 | { 12 | public class IsBlogInQueueMultiConverter : IMultiValueConverter 13 | { 14 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | var crawlingQueuelistItem = (ReadOnlyObservableList)values[0]; 17 | var currentQueuelistItem = (IBlog)values[1]; 18 | 19 | if (crawlingQueuelistItem.Any(item => item.Blog.Name.Equals(currentQueuelistItem.Name) && item.Blog.BlogType.Equals(currentQueuelistItem.BlogType))) 20 | { 21 | return true; 22 | } 23 | 24 | return false; 25 | } 26 | 27 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 28 | { 29 | throw new NotSupportedException(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/PropertyChangedEventListener.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows; 3 | 4 | namespace System.Waf.Applications 5 | { 6 | internal class PropertyChangedEventListener : IWeakEventListener 7 | { 8 | private readonly INotifyPropertyChanged source; 9 | private readonly PropertyChangedEventHandler handler; 10 | 11 | 12 | public PropertyChangedEventListener(INotifyPropertyChanged source, PropertyChangedEventHandler handler) 13 | { 14 | if (source == null) { throw new ArgumentNullException("source"); } 15 | if (handler == null) { throw new ArgumentNullException("handler"); } 16 | this.source = source; 17 | this.handler = handler; 18 | } 19 | 20 | 21 | public INotifyPropertyChanged Source { get { return source; } } 22 | 23 | public PropertyChangedEventHandler Handler { get { return handler; } } 24 | 25 | 26 | public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) 27 | { 28 | handler(sender, (PropertyChangedEventArgs)e); 29 | return true; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/MixtapeParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Crawler 7 | { 8 | public class MixtapeParser : IMixtapeParser 9 | { 10 | public Regex GetMixtapeUrlRegex() 11 | { 12 | return new Regex("(http[A-Za-z0-9_/:.]*mixtape.moe/(.*))"); 13 | } 14 | 15 | public string CreateMixtapeUrl(string mixtapeId, string detectedUrl, MixtapeTypes mixtapeType) 16 | { 17 | string url; 18 | switch (mixtapeType) 19 | { 20 | case MixtapeTypes.Mp4: 21 | url = @"https://my.mixtape.moe/" + mixtapeId + ".mp4"; 22 | break; 23 | case MixtapeTypes.Webm: 24 | url = @"https://my.mixtape.moe/" + mixtapeId + ".webm"; 25 | break; 26 | case MixtapeTypes.Any: 27 | url = detectedUrl; 28 | 29 | break; 30 | default: 31 | throw new ArgumentOutOfRangeException(); 32 | } 33 | return url; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/SelectionService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | using System.ComponentModel.Composition; 4 | using System.Waf.Foundation; 5 | 6 | using TumblThree.Applications.ObjectModel; 7 | using TumblThree.Domain.Models; 8 | 9 | namespace TumblThree.Applications.Services 10 | { 11 | [Export, Export(typeof(ISelectionService))] 12 | internal class SelectionService : Model, ISelectionService 13 | { 14 | private readonly ObservableRangeCollection selectedBlogFiles; 15 | 16 | [ImportingConstructor] 17 | public SelectionService() 18 | { 19 | selectedBlogFiles = new ObservableRangeCollection(); 20 | } 21 | 22 | public IList SelectedBlogFiles 23 | { 24 | get { return selectedBlogFiles; } 25 | } 26 | 27 | public void AddRange(IEnumerable collection) 28 | { 29 | selectedBlogFiles.AddRange(collection); 30 | } 31 | 32 | public void RemoveRange(IEnumerable collection) 33 | { 34 | selectedBlogFiles.RemoveRange(collection); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/NullImageConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace TumblThree.Presentation.Converters 7 | { 8 | public class NullImageConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | if (value == null) 13 | { 14 | return DependencyProperty.UnsetValue; 15 | } 16 | return value; 17 | } 18 | 19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 20 | { 21 | // According to https://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convertback(v=vs.110).aspx#Anchor_1 22 | // (kudos Scott Chamberlain), if you do not support a conversion 23 | // back you should return a Binding.DoNothing or a 24 | // DependencyProperty.UnsetValue 25 | return Binding.DoNothing; 26 | // Original code: 27 | // throw new NotImplementedException(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace TumblThree.Domain.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/ErrorMessagesConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Windows; 6 | using System.Windows.Data; 7 | 8 | using TumblThree.Presentation.Properties; 9 | 10 | namespace TumblThree.Presentation.Converters 11 | { 12 | public sealed class ErrorMessagesConverter : IMultiValueConverter 13 | { 14 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | var errorMessages = values?.FirstOrDefault() as IEnumerable>; 17 | if (errorMessages != null) 18 | { 19 | string message = errorMessages.Any() ? errorMessages.Last().Item2 : ""; 20 | return string.Format(CultureInfo.CurrentCulture, Resources.ErrorMessage, errorMessages.Count(), message); 21 | } 22 | return DependencyProperty.UnsetValue; 23 | } 24 | 25 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 26 | { 27 | throw new NotSupportedException(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/ProgressThrottler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Timers; 3 | 4 | namespace TumblThree.Applications 5 | { 6 | public class ProgressThrottler : IProgress 7 | { 8 | private readonly IProgress _progress; 9 | bool reportProgressAfterThrottling = true; 10 | 11 | public ProgressThrottler(IProgress progress, double interval) 12 | { 13 | var resettimer = new Timer { Interval = interval }; 14 | resettimer.Elapsed += resettimer_Elapsed; 15 | resettimer.Start(); 16 | 17 | if (progress == null) 18 | { 19 | throw new ArgumentNullException(nameof(progress)); 20 | } 21 | 22 | _progress = progress; 23 | } 24 | 25 | public void Report(T value) 26 | { 27 | if (reportProgressAfterThrottling) 28 | { 29 | _progress.Report(value); 30 | reportProgressAfterThrottling = false; 31 | } 32 | } 33 | 34 | private void resettimer_Elapsed(object sender, ElapsedEventArgs e) 35 | { 36 | reportProgressAfterThrottling = true; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace TumblThree.Applications.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/StringListToStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Windows.Data; 5 | 6 | using TumblThree.Applications.Data; 7 | 8 | namespace TumblThree.Presentation.Converters 9 | { 10 | public class StringListToStringConverter : IValueConverter 11 | { 12 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 13 | { 14 | var list = ((IEnumerable)value); 15 | return StringListConverter.ToString(list, GetSeparator(parameter)); 16 | } 17 | 18 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 19 | { 20 | var text = (string)value; 21 | return StringListConverter.FromString(text, GetSeparator(parameter)); 22 | } 23 | 24 | private static string GetSeparator(object commandParameter) 25 | { 26 | if (ConverterHelper.IsParameterSet("ListSeparator", commandParameter)) 27 | { 28 | return null; 29 | } 30 | return Environment.NewLine; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace TumblThree.Domain 7 | { 8 | public static class Logger 9 | { 10 | [Conditional("DEBUG")] 11 | public static void Verbose(string format, params object[] arguments) 12 | { 13 | Debug.WriteLine("> {0:HH:mm:ss.fff} > {1}", DateTime.Now, 14 | string.Format(CultureInfo.InvariantCulture, format, arguments)); 15 | } 16 | 17 | public static void Information(string format, params object[] arguments) 18 | { 19 | Trace.TraceInformation(format, arguments); 20 | } 21 | 22 | public static void Warning(string format, params object[] arguments) 23 | { 24 | Trace.TraceWarning(format, arguments); 25 | } 26 | 27 | public static void Error(string format, params object[] arguments) 28 | { 29 | Trace.TraceError(format, arguments); 30 | } 31 | 32 | public static string GetMemberName([CallerMemberName] string memberName = null) 33 | { 34 | return memberName; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/CollectionChangedEventListener.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Specialized; 2 | using System.Windows; 3 | 4 | namespace System.Waf.Applications 5 | { 6 | internal class CollectionChangedEventListener : IWeakEventListener 7 | { 8 | private readonly INotifyCollectionChanged source; 9 | private readonly NotifyCollectionChangedEventHandler handler; 10 | 11 | 12 | public CollectionChangedEventListener(INotifyCollectionChanged source, NotifyCollectionChangedEventHandler handler) 13 | { 14 | if (source == null) { throw new ArgumentNullException("source"); } 15 | if (handler == null) { throw new ArgumentNullException("handler"); } 16 | this.source = source; 17 | this.handler = handler; 18 | } 19 | 20 | 21 | public INotifyCollectionChanged Source { get { return source; } } 22 | 23 | public NotifyCollectionChangedEventHandler Handler { get { return handler; } } 24 | 25 | 26 | public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) 27 | { 28 | handler(sender, (NotifyCollectionChangedEventArgs)e); 29 | return true; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Controls/SuperToolTip.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace TumblThree.Presentation.Controls 5 | { 6 | public class SuperToolTip : Control 7 | { 8 | public static readonly DependencyProperty DescriptionProperty = 9 | DependencyProperty.Register(nameof(Description), typeof(string), typeof(SuperToolTip), 10 | new FrameworkPropertyMetadata("")); 11 | 12 | public static readonly DependencyProperty TitleProperty = 13 | DependencyProperty.Register(nameof(Title), typeof(string), typeof(SuperToolTip), new FrameworkPropertyMetadata("")); 14 | 15 | static SuperToolTip() 16 | { 17 | DefaultStyleKeyProperty.OverrideMetadata(typeof(SuperToolTip), new FrameworkPropertyMetadata(typeof(SuperToolTip))); 18 | } 19 | 20 | public string Title 21 | { 22 | get { return (string)GetValue(TitleProperty); } 23 | set { SetValue(TitleProperty, value); } 24 | } 25 | 26 | public string Description 27 | { 28 | get { return (string)GetValue(DescriptionProperty); } 29 | set { SetValue(DescriptionProperty, value); } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/WebmshareParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | using TumblThree.Domain.Models; 5 | 6 | namespace TumblThree.Applications.Crawler 7 | { 8 | public class WebmshareParser : IWebmshareParser 9 | { 10 | public Regex GetWebmshareUrlRegex() 11 | { 12 | return new Regex("(http[A-Za-z0-9_/:.]*webmshare.com/([A-Za-z0-9_]*))"); 13 | } 14 | 15 | public string CreateWebmshareUrl(string webshareId, string detectedUrl, WebmshareTypes webmshareType) 16 | { 17 | string url = ""; 18 | switch (webmshareType) 19 | { 20 | case WebmshareTypes.Mp4: 21 | url = @"https://s1.webmshare.com/f/" + webshareId + ".mp4"; 22 | break; 23 | case WebmshareTypes.Webm: 24 | url = @"https://s1.webmshare.com/" + webshareId + ".webm"; 25 | break; 26 | case WebmshareTypes.Any: 27 | url = detectedUrl; 28 | 29 | break; 30 | default: 31 | throw new ArgumentOutOfRangeException(); 32 | } 33 | return url; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/WindowTitleConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Waf.Foundation; 5 | using System.Windows.Data; 6 | 7 | using TumblThree.Domain.Queue; 8 | 9 | namespace TumblThree.Presentation.Converters 10 | { 11 | public class WindowTitleConverter : IMultiValueConverter 12 | { 13 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | //var stringList = values.OfType().Where(x => !string.IsNullOrEmpty(x)).ToArray(); 16 | //return string.Join(" - ", stringList); 17 | 18 | var crawlingQueuelistItem = (ReadOnlyObservableList)values[0]; 19 | if (crawlingQueuelistItem.Count() == 0) 20 | { 21 | return values[1]; 22 | } 23 | 24 | string blogStringArray = string.Join(" - ", crawlingQueuelistItem.Select(x => x.Blog.Name)); 25 | return values[1] + " - " + blogStringArray; 26 | } 27 | 28 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 29 | { 30 | throw new NotSupportedException(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Blogs/TumblrBlog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization; 5 | 6 | namespace TumblThree.Domain.Models 7 | { 8 | [DataContract] 9 | public class TumblrBlog : Blog 10 | { 11 | public static Blog Create(string url, string location) 12 | { 13 | var blog = new TumblrBlog() 14 | { 15 | Url = ExtractUrl(url), 16 | Name = ExtractName(url), 17 | BlogType = BlogTypes.tumblr, 18 | Location = location, 19 | Online = true, 20 | Version = "3", 21 | DateAdded = DateTime.Now, 22 | }; 23 | 24 | Directory.CreateDirectory(location); 25 | Directory.CreateDirectory(Path.Combine(Directory.GetParent(location).FullName, blog.Name)); 26 | 27 | blog.ChildId = Path.Combine(location, blog.Name + "_files." + blog.BlogType); 28 | if (!File.Exists(blog.ChildId)) 29 | { 30 | IFiles files = new TumblrBlogFiles(blog.Name, blog.Location); 31 | files.Save(); 32 | files = null; 33 | } 34 | return blog; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/PostCounter.cs: -------------------------------------------------------------------------------- 1 | namespace TumblThree.Domain.Models 2 | { 3 | public class PostCounter 4 | { 5 | public int AudioMetas; 6 | public int Audios; 7 | public int Conversations; 8 | public int Links; 9 | public int PhotoMetas; 10 | public int Photos; 11 | public int Quotes; 12 | public int Texts; 13 | public int Answers; 14 | public int TotalDownloads; 15 | public int VideoMetas; 16 | public int Videos; 17 | 18 | public PostCounter() 19 | { 20 | } 21 | 22 | public PostCounter(IBlog blog) 23 | { 24 | TotalDownloads = blog.DownloadedImages; 25 | Photos = blog.DownloadedPhotos; 26 | Videos = blog.DownloadedVideos; 27 | Audios = blog.DownloadedAudios; 28 | Texts = blog.DownloadedTexts; 29 | Answers = blog.DownloadedAnswers; 30 | Conversations = blog.DownloadedConversations; 31 | Quotes = blog.DownloadedQuotes; 32 | Links = blog.DownloadedLinks; 33 | PhotoMetas = blog.DownloadedPhotoMetas; 34 | VideoMetas = blog.DownloadedVideoMetas; 35 | AudioMetas = blog.DownloadedAudioMetas; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/ViewModel.Generic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace System.Waf.Applications 7 | { 8 | /// 9 | /// Abstract base class for a ViewModel implementation. 10 | /// 11 | /// The type of the view. Do provide an interface as type and not the concrete type itself. 12 | public abstract class ViewModel : ViewModel where TView : IView 13 | { 14 | private readonly TView view; 15 | 16 | 17 | /// 18 | /// Initializes a new instance of the class and attaches itself as DataContext to the view. 19 | /// 20 | /// The view. 21 | protected ViewModel(TView view) : base(view) 22 | { 23 | this.view = view; 24 | } 25 | 26 | 27 | /// 28 | /// Gets the associated view as specified view type. 29 | /// 30 | /// 31 | /// Use this property in a ViewModel class to avoid casting. 32 | /// 33 | protected TView ViewCore { get { return view; } } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DesignData/MockSelectionService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | using TumblThree.Applications.ObjectModel; 5 | using TumblThree.Applications.Services; 6 | using TumblThree.Domain.Models; 7 | 8 | namespace TumblThree.Presentation.DesignData 9 | { 10 | public class MockSelectionService : ISelectionService 11 | { 12 | private readonly ObservableRangeCollection selectedBlogFiles; 13 | 14 | public MockSelectionService() 15 | { 16 | selectedBlogFiles = new ObservableRangeCollection(); 17 | } 18 | 19 | public IList SelectedBlogFiles 20 | { 21 | get { return selectedBlogFiles; } 22 | } 23 | 24 | public void SetSelectedBlogFiles(IEnumerable blogFilesToAdd) 25 | { 26 | selectedBlogFiles.Clear(); 27 | blogFilesToAdd.ToList().ForEach(x => selectedBlogFiles.Add(x)); 28 | } 29 | 30 | public void AddRange(IEnumerable collection) 31 | { 32 | selectedBlogFiles.AddRange(collection); 33 | } 34 | 35 | public void RemoveRange(IEnumerable collection) 36 | { 37 | selectedBlogFiles.RemoveRange(collection); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/IShellService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Threading.Tasks; 5 | 6 | using TumblThree.Applications.Auth; 7 | using TumblThree.Applications.Properties; 8 | 9 | namespace TumblThree.Applications.Services 10 | { 11 | public interface IShellService : INotifyPropertyChanged 12 | { 13 | AppSettings Settings { get; } 14 | 15 | object ShellView { get; } 16 | 17 | object ContentView { get; set; } 18 | 19 | object DetailsView { get; set; } 20 | 21 | object QueueView { get; set; } 22 | 23 | object CrawlerView { get; set; } 24 | 25 | IReadOnlyCollection TasksToCompleteBeforeShutdown { get; } 26 | 27 | bool IsApplicationBusy { get; } 28 | 29 | ClipboardMonitor ClipboardMonitor { get; set; } 30 | 31 | OAuthManager OAuthManager { get; set; } 32 | 33 | event CancelEventHandler Closing; 34 | 35 | void ShowError(Exception exception, string displayMessage); 36 | 37 | void ShowDetailsView(); 38 | 39 | void UpdateDetailsView(); 40 | 41 | void ShowQueueView(); 42 | 43 | void AddTaskToCompleteBeforeShutdown(Task task); 44 | 45 | IDisposable SetApplicationBusy(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/DetailsViews/DetailsAllView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows.Input; 5 | 6 | using TumblThree.Applications.ViewModels; 7 | using TumblThree.Applications.Views; 8 | 9 | namespace TumblThree.Presentation.Views 10 | { 11 | /// 12 | /// Interaction logic for QueueView.xaml 13 | /// 14 | [Export("AllView", typeof(IDetailsView))] 15 | public partial class DetailsAllView : IDetailsView 16 | { 17 | private readonly Lazy viewModel; 18 | 19 | public DetailsAllView() 20 | { 21 | InitializeComponent(); 22 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 23 | } 24 | 25 | private DetailsAllViewModel ViewModel 26 | { 27 | get { return viewModel.Value; } 28 | } 29 | 30 | // FIXME: Implement in proper MVVM. 31 | private void Preview_OnMouseDown(object sender, MouseButtonEventArgs e) 32 | { 33 | var fullScreenMediaView = new FullScreenMediaView { DataContext = viewModel.Value.BlogFile }; 34 | fullScreenMediaView.ShowDialog(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Converter/EnumDescriptionTypeConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Reflection; 4 | 5 | namespace TumblThree.Domain.Converter 6 | { 7 | public class EnumDescriptionTypeConverter : EnumConverter 8 | { 9 | public EnumDescriptionTypeConverter(Type type) 10 | : base(type) 11 | { 12 | } 13 | 14 | public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 15 | { 16 | if (destinationType == typeof(string)) 17 | { 18 | if (value != null) 19 | { 20 | FieldInfo fi = value.GetType().GetField(value.ToString()); 21 | if (fi != null) 22 | { 23 | var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); 24 | return ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) ? attributes[0].Description : value.ToString(); 25 | } 26 | } 27 | 28 | return string.Empty; 29 | } 30 | 31 | return base.ConvertTo(context, culture, value, destinationType); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/DetailsViews/DetailsTumblrBlogView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows.Input; 5 | 6 | using TumblThree.Applications.ViewModels; 7 | using TumblThree.Applications.Views; 8 | 9 | namespace TumblThree.Presentation.Views 10 | { 11 | /// 12 | /// Interaction logic for QueueView.xaml 13 | /// 14 | [Export("TumblrBlogView", typeof(IDetailsView))] 15 | public partial class DetailsTumblrBlogView : IDetailsView 16 | { 17 | private readonly Lazy viewModel; 18 | 19 | public DetailsTumblrBlogView() 20 | { 21 | InitializeComponent(); 22 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 23 | } 24 | 25 | private DetailsTumblrBlogViewModel ViewModel 26 | { 27 | get { return viewModel.Value; } 28 | } 29 | 30 | // FIXME: Implement in proper MVVM. 31 | private void Preview_OnMouseDown(object sender, MouseButtonEventArgs e) 32 | { 33 | var fullScreenMediaView = new FullScreenMediaView { DataContext = viewModel.Value.BlogFile }; 34 | fullScreenMediaView.ShowDialog(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/DetailsViews/DetailsTumblrSearchView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows.Input; 5 | 6 | using TumblThree.Applications.ViewModels; 7 | using TumblThree.Applications.Views; 8 | 9 | namespace TumblThree.Presentation.Views 10 | { 11 | /// 12 | /// Interaction logic for QueueView.xaml 13 | /// 14 | [Export("TumblrSearchView", typeof(IDetailsView))] 15 | public partial class DetailsTumblrSearchView : IDetailsView 16 | { 17 | private readonly Lazy viewModel; 18 | 19 | public DetailsTumblrSearchView() 20 | { 21 | InitializeComponent(); 22 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 23 | } 24 | 25 | private DetailsTumblrSearchViewModel ViewModel 26 | { 27 | get { return viewModel.Value; } 28 | } 29 | 30 | // FIXME: Implement in proper MVVM. 31 | private void Preview_OnMouseDown(object sender, MouseButtonEventArgs e) 32 | { 33 | var fullScreenMediaView = new FullScreenMediaView { DataContext = viewModel.Value.BlogFile }; 34 | fullScreenMediaView.ShowDialog(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/DetailsViews/DetailsTumblrLikedByView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows.Input; 5 | 6 | using TumblThree.Applications.ViewModels; 7 | using TumblThree.Applications.Views; 8 | 9 | namespace TumblThree.Presentation.Views 10 | { 11 | /// 12 | /// Interaction logic for QueueView.xaml 13 | /// 14 | [Export("TumblrLikedByView", typeof(IDetailsView))] 15 | public partial class DetailsTumblrLikedByView : IDetailsView 16 | { 17 | private readonly Lazy viewModel; 18 | 19 | public DetailsTumblrLikedByView() 20 | { 21 | InitializeComponent(); 22 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 23 | } 24 | 25 | private DetailsTumblrLikedByViewModel ViewModel 26 | { 27 | get { return viewModel.Value; } 28 | } 29 | 30 | // FIXME: Implement in proper MVVM. 31 | private void Preview_OnMouseDown(object sender, MouseButtonEventArgs e) 32 | { 33 | var fullScreenMediaView = new FullScreenMediaView { DataContext = viewModel.Value.BlogFile }; 34 | fullScreenMediaView.ShowDialog(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/AuthenticateView.xaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/DetailsViews/DetailsTumblrTagSearchView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows.Input; 5 | 6 | using TumblThree.Applications.ViewModels; 7 | using TumblThree.Applications.Views; 8 | 9 | namespace TumblThree.Presentation.Views 10 | { 11 | /// 12 | /// Interaction logic for QueueView.xaml 13 | /// 14 | [Export("TumblrTagSearchView", typeof(IDetailsView))] 15 | public partial class DetailsTumblrTagSearchView : IDetailsView 16 | { 17 | private readonly Lazy viewModel; 18 | 19 | public DetailsTumblrTagSearchView() 20 | { 21 | InitializeComponent(); 22 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 23 | } 24 | 25 | private DetailsTumblrTagSearchViewModel ViewModel 26 | { 27 | get { return viewModel.Value; } 28 | } 29 | 30 | // FIXME: Implement in proper MVVM. 31 | private void Preview_OnMouseDown(object sender, MouseButtonEventArgs e) 32 | { 33 | var fullScreenMediaView = new FullScreenMediaView { DataContext = viewModel.Value.BlogFile }; 34 | fullScreenMediaView.ShowDialog(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/DetailsViews/DetailsTumblrHiddenBlogView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows.Input; 5 | 6 | using TumblThree.Applications.ViewModels; 7 | using TumblThree.Applications.Views; 8 | 9 | namespace TumblThree.Presentation.Views 10 | { 11 | /// 12 | /// Interaction logic for QueueView.xaml 13 | /// 14 | [Export("TumblrHiddenBlogView", typeof(IDetailsView))] 15 | public partial class DetailsTumblrHiddenBlogView : IDetailsView 16 | { 17 | private readonly Lazy viewModel; 18 | 19 | public DetailsTumblrHiddenBlogView() 20 | { 21 | InitializeComponent(); 22 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 23 | } 24 | 25 | private DetailsTumblrHiddenBlogViewModel ViewModel 26 | { 27 | get { return viewModel.Value; } 28 | } 29 | 30 | // FIXME: Implement in proper MVVM. 31 | private void Preview_OnMouseDown(object sender, MouseButtonEventArgs e) 32 | { 33 | var fullScreenMediaView = new FullScreenMediaView { DataContext = viewModel.Value.BlogFile }; 34 | fullScreenMediaView.ShowDialog(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/BrushResources.xaml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/WafConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.ComponentModel; 3 | 4 | namespace System.Waf 5 | { 6 | /// 7 | /// Configuration settings for the WPF Application Framework (WAF). 8 | /// 9 | public static class WafConfiguration 10 | { 11 | private static readonly bool isInDesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject()); 12 | #if (DEBUG) 13 | private static bool debug = true; 14 | #else 15 | private static bool debug = false; 16 | #endif 17 | 18 | 19 | /// 20 | /// Gets a value indicating whether the code is running in design mode. 21 | /// 22 | /// true if the code is running in design mode; otherwise, false. 23 | public static bool IsInDesignMode { get { return isInDesignMode; } } 24 | 25 | /// 26 | /// Obsolete: Gets or sets a value indicating whether WAF should run in Debug mode. 27 | /// 28 | /// 29 | /// The Debug mode helps to find errors in the application but it might reduce the performance. 30 | /// 31 | [Obsolete("This property is not used anymore. Please remove the code that sets this property.")] 32 | public static bool Debug 33 | { 34 | get { return debug; } 35 | set { debug = value; } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Properties/QueueSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | 5 | using TumblThree.Domain.Models; 6 | 7 | namespace TumblThree.Applications.Properties 8 | { 9 | [DataContract] 10 | public sealed class QueueSettings : IExtensibleDataObject 11 | { 12 | [DataMember(Name = "Names")] 13 | private readonly List names; 14 | 15 | [DataMember(Name = "Types")] 16 | private readonly List types; 17 | 18 | public QueueSettings() 19 | { 20 | names = new List(); 21 | types = new List(); 22 | } 23 | 24 | [DataMember] 25 | public string LastCrawledBlogName { get; set; } 26 | 27 | [DataMember] 28 | public BlogTypes LastCrawledBlogType { get; set; } 29 | 30 | public IReadOnlyList Names 31 | { 32 | get { return names; } 33 | } 34 | 35 | public IReadOnlyList Types 36 | { 37 | get { return types; } 38 | } 39 | 40 | ExtensionDataObject IExtensibleDataObject.ExtensionData { get; set; } 41 | 42 | public void ReplaceAll(IEnumerable newBlogNames, IEnumerable newBlogTypes) 43 | { 44 | names.Clear(); 45 | names.AddRange(newBlogNames); 46 | types.Clear(); 47 | types.AddRange(newBlogTypes); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/ViewModels/AuthenticateViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | 5 | using TumblThree.Applications.Services; 6 | using TumblThree.Applications.Views; 7 | 8 | namespace TumblThree.Applications.ViewModels 9 | { 10 | [Export] 11 | public class AuthenticateViewModel : ViewModel 12 | { 13 | private string oauthCallbackUrl; 14 | 15 | [ImportingConstructor] 16 | public AuthenticateViewModel(IAuthenticateView view, IShellService shellService) 17 | : base(view) 18 | { 19 | view.Closed += ViewClosed; 20 | ShellService = shellService; 21 | oauthCallbackUrl = shellService.Settings.OAuthCallbackUrl; 22 | } 23 | 24 | public IShellService ShellService { get; } 25 | 26 | public string OAuthCallbackUrl 27 | { 28 | get { return oauthCallbackUrl; } 29 | set { SetProperty(ref oauthCallbackUrl, value); } 30 | } 31 | 32 | public void ShowDialog(object owner) 33 | { 34 | ViewCore.ShowDialog(owner); 35 | } 36 | 37 | private void ViewClosed(object sender, EventArgs e) 38 | { 39 | } 40 | 41 | public void AddUrl(string url) 42 | { 43 | ViewCore.AddUrl(url); 44 | } 45 | 46 | public string GetUrl() 47 | { 48 | return ViewCore.GetUrl(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Controls/FocusAdvancement.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Input; 3 | 4 | namespace TumblThree.Presentation.Controls 5 | { 6 | public static class FocusAdvancement 7 | { 8 | public static bool GetAdvancesByEnterKey(DependencyObject obj) 9 | { 10 | return (bool)obj.GetValue(AdvancesByEnterKeyProperty); 11 | } 12 | 13 | public static void SetAdvancesByEnterKey(DependencyObject obj, bool value) 14 | { 15 | obj.SetValue(AdvancesByEnterKeyProperty, value); 16 | } 17 | 18 | public static readonly DependencyProperty AdvancesByEnterKeyProperty = 19 | DependencyProperty.RegisterAttached("AdvancesByEnterKey", typeof(bool), typeof(FocusAdvancement), 20 | new UIPropertyMetadata(OnAdvancesByEnterKeyPropertyChanged)); 21 | 22 | static void OnAdvancesByEnterKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 23 | { 24 | var element = d as UIElement; 25 | if (element == null) return; 26 | 27 | if ((bool)e.NewValue) element.KeyDown += Keydown; 28 | else element.KeyDown -= Keydown; 29 | } 30 | 31 | static void Keydown(object sender, KeyEventArgs e) 32 | { 33 | if (!e.Key.Equals(Key.Enter)) return; 34 | 35 | var element = sender as UIElement; 36 | if (element != null) element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/DetailsProgressConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | using TumblThree.Presentation.Properties; 7 | 8 | namespace TumblThree.Presentation.Converters 9 | { 10 | public class DetailsProgressConverter : IMultiValueConverter 11 | { 12 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 13 | { 14 | if (values[0] == DependencyProperty.UnsetValue) 15 | { 16 | return DependencyProperty.UnsetValue; 17 | } 18 | if (values[1] == DependencyProperty.UnsetValue) 19 | { 20 | return DependencyProperty.UnsetValue; 21 | } 22 | if (values[2] == DependencyProperty.UnsetValue) 23 | { 24 | return DependencyProperty.UnsetValue; 25 | } 26 | 27 | var downloaded = (int)values[0]; 28 | var total = (int)values[1]; 29 | int duplicates = System.Convert.ToInt32(values[2]); 30 | 31 | //if (downloaded == 0) 32 | // return ""; 33 | 34 | return string.Format(CultureInfo.CurrentCulture, Resources.DetailsProgress, downloaded, total, duplicates); 35 | } 36 | 37 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 38 | { 39 | throw new NotSupportedException(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/SettingsView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows; 5 | 6 | using TumblThree.Applications.ViewModels; 7 | using TumblThree.Applications.Views; 8 | 9 | namespace TumblThree.Presentation.Views 10 | { 11 | /// 12 | /// Interaction logic for SettingsView.xaml 13 | /// 14 | [Export(typeof(ISettingsView)), PartCreationPolicy(CreationPolicy.NonShared)] 15 | public partial class SettingsView : Window, ISettingsView 16 | { 17 | private readonly Lazy viewModel; 18 | 19 | public SettingsView() 20 | { 21 | InitializeComponent(); 22 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 23 | } 24 | 25 | private SettingsViewModel ViewModel 26 | { 27 | get { return viewModel.Value; } 28 | } 29 | 30 | public void ShowDialog(object owner) 31 | { 32 | Owner = owner as Window; 33 | ShowDialog(); 34 | } 35 | 36 | private void closeWindow(object sender, RoutedEventArgs e) 37 | { 38 | Close(); 39 | } 40 | 41 | private void Window_ContentRendered(object sender, EventArgs e) 42 | { 43 | this.MinWidth = this.ActualWidth; 44 | this.MinHeight = this.ActualHeight; 45 | this.MaxHeight = this.ActualHeight; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Services/EnvironmentService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Composition; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Waf.Applications; 7 | 8 | using TumblThree.Applications.Services; 9 | 10 | namespace TumblThree.Presentation.Services 11 | { 12 | [Export(typeof(IEnvironmentService))] 13 | internal class EnvironmentService : IEnvironmentService 14 | { 15 | private readonly Lazy appSettingsPath; 16 | private readonly Lazy profilePath; 17 | private readonly Lazy> queueList; 18 | 19 | public EnvironmentService() 20 | { 21 | queueList = new Lazy>(() => Environment.GetCommandLineArgs().Skip(1).ToArray()); 22 | profilePath = new Lazy(() => 23 | Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ApplicationInfo.Company, 24 | ApplicationInfo.ProductName, "ProfileOptimization")); 25 | appSettingsPath = new Lazy(() => 26 | Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ApplicationInfo.Company, 27 | ApplicationInfo.ProductName, "Settings")); 28 | } 29 | 30 | public string ProfilePath 31 | { 32 | get { return profilePath.Value; } 33 | } 34 | 35 | public string AppSettingsPath 36 | { 37 | get { return appSettingsPath.Value; } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/RateLimiter/RateLimiter/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RateLimiter")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("RateLimiter")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5b56eeeb-9107-4fc5-bd73-10fe96c9bded")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | [assembly: InternalsVisibleTo("Guava.RateLimiter.Tests")] -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Blogs/TumblrHiddenBlog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization; 5 | 6 | namespace TumblThree.Domain.Models 7 | { 8 | [DataContract] 9 | public class TumblrHiddenBlog : Blog 10 | { 11 | public static Blog Create(string url, string location) 12 | { 13 | var blog = new TumblrHiddenBlog() 14 | { 15 | Url = ExtractUrl(url), 16 | Name = ExtractName(url), 17 | BlogType = BlogTypes.tmblrpriv, 18 | Location = location, 19 | Online = true, 20 | Version = "3", 21 | DateAdded = DateTime.Now, 22 | }; 23 | 24 | Directory.CreateDirectory(location); 25 | Directory.CreateDirectory(Path.Combine(Directory.GetParent(location).FullName, blog.Name)); 26 | 27 | blog.ChildId = Path.Combine(location, blog.Name + "_files." + blog.BlogType); 28 | if (!File.Exists(blog.ChildId)) 29 | { 30 | IFiles files = new TumblrHiddenBlogFiles(blog.Name, blog.Location); 31 | files.Save(); 32 | files = null; 33 | } 34 | return blog; 35 | } 36 | 37 | protected static new string ExtractName(string url) 38 | { 39 | return url.Split('/')[5]; 40 | } 41 | 42 | protected static new string ExtractUrl(string url) 43 | { 44 | return "https://" + ExtractName(url) + ".tumblr.com/"; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/FullScreenMediaView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows; 5 | using System.Windows.Input; 6 | 7 | using TumblThree.Applications.ViewModels; 8 | using TumblThree.Applications.Views; 9 | 10 | namespace TumblThree.Presentation.Views 11 | { 12 | /// 13 | /// Interaction logic for FullScreenMediaView.xaml 14 | /// 15 | [Export(typeof(IFullScreenMediaView)), PartCreationPolicy(CreationPolicy.NonShared)] 16 | public partial class FullScreenMediaView : Window, IFullScreenMediaView 17 | { 18 | private readonly Lazy viewModel; 19 | 20 | public FullScreenMediaView() 21 | { 22 | InitializeComponent(); 23 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 24 | this.PreviewKeyDown += new KeyEventHandler(HandleEsc); 25 | } 26 | 27 | private FullScreenMediaViewModel ViewModel 28 | { 29 | get { return viewModel.Value; } 30 | } 31 | 32 | public void ShowDialog(object owner) 33 | { 34 | Owner = owner as Window; 35 | ShowDialog(); 36 | } 37 | 38 | private void HandleEsc(object sender, KeyEventArgs e) 39 | { 40 | if (e.Key == Key.Escape) 41 | Close(); 42 | } 43 | 44 | private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e) 45 | { 46 | this.Close(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DesignData/MockManagerService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | 6 | using TumblThree.Applications.Services; 7 | using TumblThree.Domain.Models; 8 | 9 | namespace TumblThree.Presentation.DesignData 10 | { 11 | public class MockManagerService : IManagerService 12 | { 13 | private readonly ObservableCollection blogFiles; 14 | private readonly ObservableCollection innerBlogFiles; 15 | 16 | public MockManagerService() 17 | { 18 | innerBlogFiles = new ObservableCollection(); 19 | blogFiles = new ObservableCollection(innerBlogFiles); 20 | } 21 | 22 | public ObservableCollection BlogFiles 23 | { 24 | get { return blogFiles; } 25 | } 26 | 27 | public IEnumerable Databases { get; } 28 | 29 | public void SetBlogFiles(IEnumerable blogFilesToAdd) 30 | { 31 | innerBlogFiles.Clear(); 32 | blogFilesToAdd.ToList().ForEach(x => innerBlogFiles.Add(x)); 33 | } 34 | 35 | public bool CheckIfFileExistsInDB(string url) 36 | { 37 | return false; 38 | } 39 | 40 | public void AddDatabase(IFiles database) 41 | { 42 | throw new NotImplementedException(); 43 | } 44 | 45 | public void RemoveDatabase(IFiles database) 46 | { 47 | throw new NotImplementedException(); 48 | } 49 | 50 | public void ClearDatabases() 51 | { 52 | throw new NotImplementedException(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Presentation/ValidationReloadedTracker.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Windows; 3 | using System.Windows.Controls; 4 | 5 | namespace System.Waf.Presentation 6 | { 7 | // This class stores the ValidationErrors of an unloaded Control. When the Control is loaded again then 8 | // it restores the ValidationErrors. 9 | internal class ValidationReloadedTracker 10 | { 11 | private readonly ValidationTracker validationTracker; 12 | private readonly IEnumerable errors; 13 | 14 | 15 | public ValidationReloadedTracker(ValidationTracker validationTracker, object validationSource, 16 | IEnumerable errors) 17 | { 18 | this.validationTracker = validationTracker; 19 | this.errors = errors; 20 | 21 | if (validationSource is FrameworkElement) 22 | { 23 | ((FrameworkElement)validationSource).Loaded += ValidationSourceLoaded; 24 | } 25 | else 26 | { 27 | ((FrameworkContentElement)validationSource).Loaded += ValidationSourceLoaded; 28 | } 29 | } 30 | 31 | 32 | private void ValidationSourceLoaded(object sender, RoutedEventArgs e) 33 | { 34 | if (sender is FrameworkElement) 35 | { 36 | ((FrameworkElement)sender).Loaded -= ValidationSourceLoaded; 37 | } 38 | else 39 | { 40 | ((FrameworkContentElement)sender).Loaded -= ValidationSourceLoaded; 41 | } 42 | 43 | validationTracker.AddErrors(sender, errors); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Foundation/DataErrorInfoExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace System.Waf.Foundation 4 | { 5 | /// 6 | /// Extends the interface with new Validation methods. 7 | /// 8 | public static class DataErrorInfoExtensions 9 | { 10 | /// 11 | /// Validates the specified object. 12 | /// 13 | /// The object to validate. 14 | /// An error message indicating what is wrong with this object. The default is an empty string (""). 15 | /// The argument instance must not be null. 16 | public static string Validate(this IDataErrorInfo instance) 17 | { 18 | if (instance == null) { throw new ArgumentNullException("instance"); } 19 | 20 | return instance.Error ?? ""; 21 | } 22 | 23 | /// 24 | /// Validates the specified member of the object. 25 | /// 26 | /// The object to validate. 27 | /// The name of the member to validate. 28 | /// The error message for the member. The default is an empty string (""). 29 | /// The argument instance must not be null. 30 | public static string Validate(this IDataErrorInfo instance, string memberName) 31 | { 32 | if (instance == null) { throw new ArgumentNullException("instance"); } 33 | 34 | return instance[memberName] ?? ""; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ICrawlerService.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using System.Waf.Foundation; 5 | using System.Windows.Input; 6 | 7 | using Guava.RateLimiter; 8 | 9 | using TumblThree.Domain.Queue; 10 | 11 | namespace TumblThree.Applications.Services 12 | { 13 | public interface ICrawlerService : INotifyPropertyChanged 14 | { 15 | ICommand AddBlogCommand { get; set; } 16 | 17 | ICommand RemoveBlogCommand { get; set; } 18 | 19 | ICommand ShowFilesCommand { get; set; } 20 | 21 | ICommand EnqueueSelectedCommand { get; set; } 22 | 23 | ICommand LoadLibraryCommand { get; set; } 24 | 25 | ICommand LoadAllDatabasesCommand { get; set; } 26 | 27 | ICommand RemoveBlogFromQueueCommand { get; set; } 28 | 29 | ICommand ListenClipboardCommand { get; set; } 30 | 31 | ICommand CrawlCommand { get; set; } 32 | 33 | ICommand PauseCommand { get; set; } 34 | 35 | ICommand ResumeCommand { get; set; } 36 | 37 | ICommand StopCommand { get; set; } 38 | 39 | ICommand AutoDownloadCommand { get; set; } 40 | 41 | bool IsCrawl { get; set; } 42 | 43 | bool IsPaused { get; set; } 44 | 45 | bool IsTimerSet { get; set; } 46 | 47 | string NewBlogUrl { get; set; } 48 | 49 | IReadOnlyObservableList ActiveItems { get; } 50 | 51 | RateLimiter Timeconstraint { get; set; } 52 | 53 | Timer Timer { get; set; } 54 | 55 | TaskCompletionSource DatabasesLoaded { get; set; } 56 | 57 | void AddActiveItems(QueueListItem itemToAdd); 58 | 59 | void RemoveActiveItem(QueueListItem itemToRemove); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Blogs/TumblrLikedByBlog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization; 5 | 6 | namespace TumblThree.Domain.Models 7 | { 8 | [DataContract] 9 | public class TumblrLikedByBlog : Blog 10 | { 11 | public static Blog Create(string url, string location) 12 | { 13 | var blog = new TumblrLikedByBlog() 14 | { 15 | Url = ExtractUrl(url), 16 | Name = ExtractName(url), 17 | BlogType = BlogTypes.tlb, 18 | Location = location, 19 | Online = true, 20 | Version = "3", 21 | DateAdded = DateTime.Now, 22 | }; 23 | 24 | Directory.CreateDirectory(location); 25 | Directory.CreateDirectory(Path.Combine(Directory.GetParent(location).FullName, blog.Name)); 26 | 27 | blog.ChildId = Path.Combine(location, blog.Name + "_files." + blog.BlogType); 28 | if (!File.Exists(blog.ChildId)) 29 | { 30 | IFiles files = new TumblrLikedByBlogFiles(blog.Name, blog.Location); 31 | files.Save(); 32 | files = null; 33 | } 34 | return blog; 35 | } 36 | 37 | protected static new string ExtractName(string url) 38 | { 39 | return url.Split('/')[5]; 40 | } 41 | 42 | protected static new string ExtractUrl(string url) 43 | { 44 | if (url.StartsWith("http://")) 45 | url = url.Insert(4, "s"); 46 | int blogNameLength = url.Split('/')[5].Length; 47 | var urlLength = 32; 48 | return url.Substring(0, blogNameLength + urlLength); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/RatingToStarsConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace TumblThree.Presentation.Converters 6 | { 7 | public class RatingToStarsConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | int rating = System.Convert.ToInt32(value, CultureInfo.InvariantCulture); 12 | if (rating >= 99) 13 | { 14 | return 5; 15 | } 16 | else if (rating >= 75) 17 | { 18 | return 4; 19 | } 20 | else if (rating >= 50) 21 | { 22 | return 3; 23 | } 24 | else if (rating >= 25) 25 | { 26 | return 2; 27 | } 28 | else if (rating >= 1) 29 | { 30 | return 1; 31 | } 32 | return 0; 33 | } 34 | 35 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 36 | { 37 | int stars = System.Convert.ToInt32(value, CultureInfo.InvariantCulture); 38 | if (stars == 5) 39 | { 40 | return 99; 41 | } 42 | else if (stars == 4) 43 | { 44 | return 75; 45 | } 46 | else if (stars == 3) 47 | { 48 | return 50; 49 | } 50 | else if (stars == 2) 51 | { 52 | return 25; 53 | } 54 | else if (stars == 1) 55 | { 56 | return 1; 57 | } 58 | return 0; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Extensions/EnumBindingSourceExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Markup; 3 | 4 | namespace TumblThree.Presentation.Extensions 5 | { 6 | public class EnumBindingSourceExtension : MarkupExtension 7 | { 8 | private Type _enumType; 9 | public Type EnumType 10 | { 11 | get { return this._enumType; } 12 | set 13 | { 14 | if (value != this._enumType) 15 | { 16 | if (null != value) 17 | { 18 | Type enumType = Nullable.GetUnderlyingType(value) ?? value; 19 | 20 | if (!enumType.IsEnum) 21 | throw new ArgumentException("Type must be for an Enum."); 22 | } 23 | 24 | this._enumType = value; 25 | } 26 | } 27 | } 28 | 29 | public EnumBindingSourceExtension() { } 30 | 31 | public EnumBindingSourceExtension(Type enumType) 32 | { 33 | this.EnumType = enumType; 34 | } 35 | 36 | public override object ProvideValue(IServiceProvider serviceProvider) 37 | { 38 | if (null == this._enumType) 39 | throw new InvalidOperationException("The EnumType must be specified."); 40 | 41 | Type actualEnumType = Nullable.GetUnderlyingType(this._enumType) ?? this._enumType; 42 | Array enumValues = Enum.GetValues(actualEnumType); 43 | 44 | if (actualEnumType == this._enumType) 45 | return enumValues; 46 | 47 | Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1); 48 | enumValues.CopyTo(tempArray, 1); 49 | return tempArray; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Blogs/TumblrTagSearchBlog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization; 5 | 6 | namespace TumblThree.Domain.Models 7 | { 8 | [DataContract] 9 | public class TumblrTagSearchBlog : Blog 10 | { 11 | public static Blog Create(string url, string location) 12 | { 13 | var blog = new TumblrTagSearchBlog() 14 | { 15 | Url = ExtractUrl(url), 16 | Name = ExtractName(url), 17 | BlogType = BlogTypes.tumblrtagsearch, 18 | Location = location, 19 | Online = true, 20 | Version = "3", 21 | DateAdded = DateTime.Now, 22 | }; 23 | 24 | Directory.CreateDirectory(location); 25 | Directory.CreateDirectory(Path.Combine(Directory.GetParent(location).FullName, blog.Name)); 26 | 27 | blog.ChildId = Path.Combine(location, blog.Name + "_files." + blog.BlogType); 28 | if (!File.Exists(blog.ChildId)) 29 | { 30 | IFiles files = new TumblrTagSearchBlogFiles(blog.Name, blog.Location); 31 | files.Save(); 32 | files = null; 33 | } 34 | return blog; 35 | } 36 | 37 | protected static new string ExtractName(string url) 38 | { 39 | return url.Split('/')[4].Replace("-", "+"); 40 | } 41 | 42 | protected static new string ExtractUrl(string url) 43 | { 44 | if (url.StartsWith("http://")) 45 | url = url.Insert(4, "s"); 46 | int blogNameLength = url.Split('/')[4].Length; 47 | var urlLength = 30; 48 | return url.Substring(0, blogNameLength + urlLength); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/Blogs/TumblrSearchBlog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization; 5 | 6 | namespace TumblThree.Domain.Models 7 | { 8 | [DataContract] 9 | public class TumblrSearchBlog : Blog 10 | { 11 | public static Blog Create(string url, string location) 12 | { 13 | var blog = new TumblrSearchBlog() 14 | { 15 | Url = ExtractUrl(url), 16 | Name = ExtractName(url), 17 | BlogType = BlogTypes.tumblrsearch, 18 | Location = location, 19 | Online = true, 20 | Version = "3", 21 | DateAdded = DateTime.Now, 22 | PageSize = 20, 23 | }; 24 | 25 | Directory.CreateDirectory(location); 26 | Directory.CreateDirectory(Path.Combine(Directory.GetParent(location).FullName, blog.Name)); 27 | 28 | blog.ChildId = Path.Combine(location, blog.Name + "_files." + blog.BlogType); 29 | if (!File.Exists(blog.ChildId)) 30 | { 31 | IFiles files = new TumblrSearchBlogFiles(blog.Name, blog.Location); 32 | files.Save(); 33 | files = null; 34 | } 35 | return blog; 36 | } 37 | 38 | protected static new string ExtractName(string url) 39 | { 40 | return url.Split('/')[4].Replace("-", "+"); 41 | } 42 | 43 | protected static new string ExtractUrl(string url) 44 | { 45 | if (url.StartsWith("http://")) 46 | url = url.Insert(4, "s"); 47 | int blogNameLength = url.Split('/')[4].Length; 48 | var urlLength = 30; 49 | return url.Substring(0, blogNameLength + urlLength); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/ViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Windows.Threading; 3 | 4 | namespace System.Waf.Applications 5 | { 6 | /// 7 | /// Abstract base class for a ViewModel implementation. 8 | /// 9 | #pragma warning disable 618 10 | public abstract class ViewModel : DataModel 11 | #pragma warning restore 618 12 | { 13 | private readonly IView view; 14 | 15 | 16 | /// 17 | /// Initializes a new instance of the class and attaches itself as DataContext to the view. 18 | /// 19 | /// The view. 20 | protected ViewModel(IView view) 21 | { 22 | if (view == null) { throw new ArgumentNullException("view"); } 23 | this.view = view; 24 | 25 | // Check if the code is running within the WPF application model 26 | if (SynchronizationContext.Current is DispatcherSynchronizationContext) 27 | { 28 | // Set DataContext of the view has to be delayed so that the ViewModel can initialize the internal data (e.g. Commands) 29 | // before the view starts with DataBinding. 30 | Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate() 31 | { 32 | this.view.DataContext = this; 33 | }); 34 | } 35 | else 36 | { 37 | // When the code runs outside of the WPF application model then we set the DataContext immediately. 38 | view.DataContext = this; 39 | } 40 | } 41 | 42 | 43 | /// 44 | /// Gets the associated view. 45 | /// 46 | public object View { get { return view; } } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/BlogFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | 4 | namespace TumblThree.Domain.Models 5 | { 6 | [Export(typeof(IBlogFactory))] 7 | public class BlogFactory : IBlogFactory 8 | { 9 | IUrlValidator urlValidator; 10 | 11 | [ImportingConstructor] 12 | internal BlogFactory(IUrlValidator urlValidator) 13 | { 14 | this.urlValidator = urlValidator; 15 | } 16 | 17 | public bool IsValidTumblrBlogUrl(string blogUrl) 18 | { 19 | blogUrl = urlValidator.AddHttpsProtocol(blogUrl); 20 | return urlValidator.IsValidTumblrUrl(blogUrl) 21 | || urlValidator.IsValidTumblrHiddenUrl(blogUrl) 22 | || urlValidator.IsValidTumblrLikedByUrl(blogUrl) 23 | || urlValidator.IsValidTumblrSearchUrl(blogUrl) 24 | || urlValidator.IsValidTumblrTagSearchUrl(blogUrl); 25 | } 26 | 27 | public IBlog GetBlog(string blogUrl, string path) 28 | { 29 | blogUrl = urlValidator.AddHttpsProtocol(blogUrl); 30 | if (urlValidator.IsValidTumblrUrl(blogUrl)) 31 | return TumblrBlog.Create(blogUrl, path); 32 | if (urlValidator.IsValidTumblrHiddenUrl(blogUrl)) 33 | return TumblrHiddenBlog.Create(blogUrl, path); 34 | if (urlValidator.IsValidTumblrLikedByUrl(blogUrl)) 35 | return TumblrLikedByBlog.Create(blogUrl, path); 36 | if (urlValidator.IsValidTumblrSearchUrl(blogUrl)) 37 | return TumblrSearchBlog.Create(blogUrl, path); 38 | if (urlValidator.IsValidTumblrTagSearchUrl(blogUrl)) 39 | return TumblrTagSearchBlog.Create(blogUrl, path); 40 | throw new ArgumentException("Website is not supported!", nameof(blogUrl)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/RateLimiter/RateLimiter/SleepingStopwatch.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Threading; 3 | 4 | namespace Guava.RateLimiter 5 | { 6 | public interface ISleepingStopwatch 7 | { 8 | long ReadMicros(); 9 | void SleepMicrosUninterruptibly(long micros); 10 | } 11 | 12 | public sealed class SleepingStopwatch : ISleepingStopwatch 13 | { 14 | private SleepingStopwatch() 15 | { 16 | _stopwatch = Stopwatch.StartNew(); 17 | } 18 | 19 | /// 20 | /// We always hold the mutex when calling this. 21 | /// 22 | private readonly Stopwatch _stopwatch; 23 | 24 | public long ReadMicros() 25 | { 26 | if (!Stopwatch.IsHighResolution) 27 | return _stopwatch.ElapsedMilliseconds * 1000; //_stopwatch.ElapsedTicks / Stopwatch.Frequency; 28 | 29 | return _stopwatch.ElapsedTicks * 1000000 / Stopwatch.Frequency; 30 | } 31 | 32 | public void SleepMicrosUninterruptibly(long micros) 33 | { 34 | //converting microseconds to ticks 35 | var expectedTicks = _stopwatch.ElapsedTicks + micros * Stopwatch.Frequency / 1000000;//frequency = N of ticks per 1 second 36 | 37 | if (micros > 40000 || !Stopwatch.IsHighResolution)//32ms is the precision of DateTime which is used inside SpinUntil 38 | { 39 | //leaving some residual time after spinUntil to spin accurately 40 | SpinWait.SpinUntil(() => _stopwatch.ElapsedTicks >= expectedTicks, (int)(micros / 1000) - 10); 41 | } 42 | 43 | while (_stopwatch.ElapsedTicks < expectedTicks) 44 | { 45 | Thread.SpinWait(1); 46 | } 47 | } 48 | 49 | public static SleepingStopwatch CreateFromSystemTimer() 50 | { 51 | return new SleepingStopwatch(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace TumblThree.Presentation.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("")] 29 | public string Culture { 30 | get { 31 | return ((string)(this["Culture"])); 32 | } 33 | } 34 | 35 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 36 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 37 | [global::System.Configuration.DefaultSettingValueAttribute("")] 38 | public string UICulture { 39 | get { 40 | return ((string)(this["UICulture"])); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DesignData/SampleShellViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Controls; 4 | 5 | using TumblThree.Applications.ViewModels; 6 | using TumblThree.Applications.Views; 7 | 8 | namespace TumblThree.Presentation.DesignData 9 | { 10 | public class SampleShellViewModel : ShellViewModel 11 | { 12 | public SampleShellViewModel() : base(new MockShellView(), new MockShellService(), new MockCrawlerService(), null, null) 13 | { 14 | ShellService.QueueView = new Control(); 15 | IsQueueViewVisible = true; 16 | ShowError(null, "Error Message: Could not load blog: nature-wallpaper"); 17 | } 18 | 19 | private class MockShellView : MockView, IShellView 20 | { 21 | public double VirtualScreenWidth 22 | { 23 | get { return 0; } 24 | } 25 | 26 | public double VirtualScreenHeight 27 | { 28 | get { return 0; } 29 | } 30 | 31 | public double Left { get; set; } 32 | 33 | public double Top { get; set; } 34 | 35 | public double Width { get; set; } 36 | 37 | public double Height { get; set; } 38 | 39 | public bool IsMaximized { get; set; } 40 | 41 | public double GridSplitterPosition { get; set; } 42 | 43 | public event CancelEventHandler Closing; 44 | 45 | public event EventHandler Closed; 46 | 47 | public void Show() 48 | { 49 | } 50 | 51 | public void Close() 52 | { 53 | } 54 | 55 | protected virtual void OnClosing(CancelEventArgs e) 56 | { 57 | Closing?.Invoke(this, e); 58 | } 59 | 60 | protected virtual void OnClosed(EventArgs e) 61 | { 62 | Closed?.Invoke(this, e); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DesignData/SampleDetailsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using TumblThree.Applications.ViewModels; 4 | using TumblThree.Applications.Views; 5 | using TumblThree.Domain.Models; 6 | 7 | namespace TumblThree.Presentation.DesignData 8 | { 9 | public class SampleDetailsViewModel : DetailsAllViewModel 10 | { 11 | public SampleDetailsViewModel() : base(new MockDetailsView(), null) 12 | { 13 | var BlogFile = new[] 14 | { 15 | new Blog 16 | { 17 | Name = "Nature Wallpapers", 18 | Url = "http://nature-wallpaper.tumblr.com/", 19 | DownloadedImages = 123, 20 | DateAdded = DateTime.Now, 21 | Progress = 66, 22 | TotalCount = 234, 23 | }, 24 | new Blog 25 | { 26 | Name = "Landscape Wallpapers", 27 | Url = "http://landscape-wallpaper.tumblr.com/", 28 | DownloadedImages = 17236, 29 | DateAdded = DateTime.Now, 30 | Progress = 95, 31 | TotalCount = 15739, 32 | }, 33 | new Blog 34 | { 35 | Name = "FX Wallpapers", 36 | Url = "http://nature-wallpaper.tumblr.com/", 37 | DownloadedImages = 12845, 38 | DateAdded = DateTime.Now, 39 | Progress = 12, 40 | TotalCount = 82453, 41 | Posts = 912713, 42 | Texts = 10299, 43 | Photos = 69418, 44 | Videos = 7435, 45 | Conversations = 891, 46 | NumberOfLinks = 0, 47 | } 48 | }; 49 | Count = 1; 50 | } 51 | 52 | private class MockDetailsView : MockView, IDetailsView 53 | { 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/TumblrSvcJsonToJson.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.Serialization.Json; 3 | using System.Text; 4 | using TumblThree.Applications.DataModels.TumblrSvcJson; 5 | using TumblThree.Domain; 6 | 7 | namespace TumblThree.Applications.Parser 8 | { 9 | public class TumblrSvcJsonToJsonParser : ITumblrToTextParser where T : Post 10 | { 11 | public string ParseText(T post) 12 | { 13 | return GetPostAsString(post); 14 | } 15 | 16 | public string ParseQuote(T post) 17 | { 18 | return GetPostAsString(post); 19 | } 20 | 21 | public string ParseLink(T post) 22 | { 23 | return GetPostAsString(post); 24 | } 25 | 26 | public string ParseConversation(T post) 27 | { 28 | return GetPostAsString(post); 29 | } 30 | 31 | public string ParseAnswer(T post) 32 | { 33 | return GetPostAsString(post); 34 | } 35 | 36 | public string ParsePhotoMeta(T post) 37 | { 38 | return GetPostAsString(post); 39 | } 40 | 41 | public string ParseVideoMeta(T post) 42 | { 43 | return GetPostAsString(post); 44 | } 45 | 46 | public string ParseAudioMeta(T post) 47 | { 48 | return GetPostAsString(post); 49 | } 50 | 51 | private string GetPostAsString(T post) 52 | { 53 | var postCopy = (Post)post.Clone(); 54 | postCopy.blog = null; 55 | postCopy.trail = null; 56 | postCopy.share_popover_data = null; 57 | 58 | DataContractJsonSerializer serializer = new DataContractJsonSerializer(postCopy.GetType()); 59 | 60 | using (MemoryStream ms = new MemoryStream()) 61 | { 62 | serializer.WriteObject(ms, postCopy); 63 | return JsonFormatter.FormatOutput(Encoding.UTF8.GetString(ms.ToArray())); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Converters/BlogtypeToDisplayValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.Windows.Data; 5 | 6 | using TumblThree.Domain.Models; 7 | using TumblThree.Presentation.Properties; 8 | 9 | namespace TumblThree.Presentation.Converters 10 | { 11 | public class BlogtypeToDisplayValueConverter : IValueConverter 12 | { 13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | BlogTypes type = (BlogTypes)value; 16 | switch (type) 17 | { 18 | case BlogTypes.tumblr: 19 | return string.Format(CultureInfo.CurrentCulture, Resources.BlogtypeTumblr); 20 | case BlogTypes.tmblrpriv: 21 | return string.Format(CultureInfo.CurrentCulture, Resources.BlogtypeTumblrPrivate); 22 | case BlogTypes.tumblrsearch: 23 | return string.Format(CultureInfo.CurrentCulture, Resources.BlogtypeTumblrSearch); 24 | case BlogTypes.tumblrtagsearch: 25 | return string.Format(CultureInfo.CurrentCulture, Resources.BlogtypeTumblrTagSearch); 26 | case BlogTypes.tlb: 27 | return string.Format(CultureInfo.CurrentCulture, Resources.BlogtypeTumblrLikedBy); 28 | case BlogTypes.instagram: 29 | return string.Format(CultureInfo.CurrentCulture, Resources.BlogtypeInstagram); 30 | case BlogTypes.twitter: 31 | return string.Format(CultureInfo.CurrentCulture, Resources.BlogtypeTwitter); 32 | case BlogTypes.all: 33 | return ""; 34 | default: 35 | return ""; 36 | } 37 | } 38 | 39 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 40 | { 41 | throw new NotImplementedException(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Foundation/CollectionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace System.Waf.Foundation 7 | { 8 | /// 9 | /// Provides helper methods for collections. 10 | /// 11 | public static class CollectionHelper 12 | { 13 | /// 14 | /// Gets the next element in the collection or default when no next element can be found. 15 | /// 16 | /// The type of the items. 17 | /// The collection. 18 | /// The current item. 19 | /// The next element in the collection or default when no next element can be found. 20 | /// collection must not be null. 21 | /// The collection does not contain the specified current item. 22 | public static T GetNextElementOrDefault(IEnumerable collection, T current) 23 | { 24 | if (collection == null) { throw new ArgumentNullException("collection"); } 25 | 26 | bool found = false; 27 | IEnumerator enumerator = collection.GetEnumerator(); 28 | while (enumerator.MoveNext()) 29 | { 30 | if (EqualityComparer.Default.Equals(enumerator.Current, current)) 31 | { 32 | found = true; 33 | break; 34 | } 35 | } 36 | if (!found) 37 | { 38 | throw new ArgumentException("The collection does not contain the current item."); 39 | } 40 | 41 | if (enumerator.MoveNext()) 42 | { 43 | return enumerator.Current; 44 | } 45 | else 46 | { 47 | return default(T); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/Services/FileDialogResult.cs: -------------------------------------------------------------------------------- 1 | namespace System.Waf.Applications.Services 2 | { 3 | /// 4 | /// Contains the result information about the work with the file dialog box. 5 | /// 6 | public class FileDialogResult 7 | { 8 | private readonly string fileName; 9 | private readonly FileType selectedFileType; 10 | 11 | 12 | /// 13 | /// Initializes a new instance of the class with null values. 14 | /// Use this constructor when the user canceled the file dialog box. 15 | /// 16 | public FileDialogResult() : this(null, null) 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The filename entered by the user. 24 | /// The file type selected by the user. 25 | public FileDialogResult(string fileName, FileType selectedFileType) 26 | { 27 | this.fileName = fileName; 28 | this.selectedFileType = selectedFileType; 29 | } 30 | 31 | 32 | /// 33 | /// Gets a value indicating whether this instance contains valid data. This property returns false 34 | /// when the user canceled the file dialog box. 35 | /// 36 | public bool IsValid { get { return FileName != null && SelectedFileType != null; } } 37 | 38 | /// 39 | /// Gets the filename entered by the user or null when the user canceled the dialog box. 40 | /// 41 | public string FileName { get { return fileName; } } 42 | 43 | /// 44 | /// Gets the file type selected by the user or null when the user canceled the dialog box. 45 | /// 46 | public FileType SelectedFileType { get { return selectedFileType; } } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Applications/ViewHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Windows.Threading; 3 | using System.Threading; 4 | 5 | namespace System.Waf.Applications 6 | { 7 | /// 8 | /// Provides helper methods that perform common tasks involving a view. 9 | /// 10 | public static class ViewHelper 11 | { 12 | /// 13 | /// Gets the ViewModel which is associated with the specified view. 14 | /// 15 | /// The view. 16 | /// The associated ViewModel, or null when no ViewModel was found. 17 | /// view must not be null. 18 | public static ViewModel GetViewModel(this IView view) 19 | { 20 | if (view == null) { throw new ArgumentNullException("view"); } 21 | 22 | object dataContext = view.DataContext; 23 | // When the DataContext is null then it might be that the ViewModel hasn't set it yet. 24 | // Enforce it by executing the event queue of the Dispatcher. 25 | if (dataContext == null && SynchronizationContext.Current is DispatcherSynchronizationContext) 26 | { 27 | DispatcherHelper.DoEvents(); 28 | dataContext = view.DataContext; 29 | } 30 | return dataContext as ViewModel; 31 | } 32 | 33 | /// 34 | /// Gets the ViewModel which is associated with the specified view. 35 | /// 36 | /// The type of the ViewModel 37 | /// The view. 38 | /// The associated ViewModel, or null when no ViewModel was found. 39 | /// view must not be null. 40 | public static T GetViewModel(this IView view) where T : ViewModel 41 | { 42 | return GetViewModel(view) as T; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Parser/ImgurParser.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Text.RegularExpressions; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using TumblThree.Applications.Extensions; 6 | using TumblThree.Applications.Properties; 7 | 8 | namespace TumblThree.Applications.Crawler 9 | { 10 | public class ImgurParser : IImgurParser 11 | { 12 | private readonly AppSettings settings; 13 | private readonly IWebRequestFactory webRequestFactory; 14 | private readonly CancellationToken ct; 15 | 16 | public ImgurParser(AppSettings settings, IWebRequestFactory webRequestFactory, CancellationToken ct) 17 | { 18 | this.settings = settings; 19 | this.webRequestFactory = webRequestFactory; 20 | this.ct = ct; 21 | } 22 | 23 | public Regex GetImgurImageRegex() 24 | { 25 | return new Regex("(http[A-Za-z0-9_/:.]*i.imgur.com/([A-Za-z0-9_]*)(.jpg|.png|.gif|.gifv))"); 26 | } 27 | 28 | public Regex GetImgurAlbumRegex() 29 | { 30 | return new Regex("(http[A-Za-z0-9_/:.]*imgur.com/[aA]/([A-Za-z0-9_]*))"); 31 | } 32 | 33 | public Regex GetImgurAlbumHashRegex() 34 | { 35 | return new Regex("\"hash\":\"([a-zA-Z0-9]*)\""); 36 | } 37 | 38 | public Regex GetImgurAlbumExtRegex() 39 | { 40 | return new Regex("\"ext\":\"([.a-zA-Z0-9]*)\""); 41 | } 42 | 43 | public virtual async Task RequestImgurAlbumSite(string imgurAlbumUrl) 44 | { 45 | var requestRegistration = new CancellationTokenRegistration(); 46 | try 47 | { 48 | HttpWebRequest request = webRequestFactory.CreateGetReqeust(imgurAlbumUrl); 49 | requestRegistration = ct.Register(() => request.Abort()); 50 | return await webRequestFactory.ReadReqestToEnd(request).TimeoutAfter(settings.TimeOut); 51 | } 52 | finally 53 | { 54 | requestRegistration.Dispose(); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Views/ShellWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using System.Waf.Applications; 4 | using System.Windows; 5 | using System.Windows.Input; 6 | 7 | using TumblThree.Applications.ViewModels; 8 | using TumblThree.Applications.Views; 9 | 10 | namespace TumblThree.Presentation.Views 11 | { 12 | [Export(typeof(IShellView))] 13 | public partial class ShellWindow : Window, IShellView 14 | { 15 | private readonly Lazy viewModel; 16 | 17 | public ShellWindow() 18 | { 19 | InitializeComponent(); 20 | viewModel = new Lazy(() => ViewHelper.GetViewModel(this)); 21 | } 22 | 23 | private ShellViewModel ViewModel 24 | { 25 | get { return viewModel.Value; } 26 | } 27 | 28 | public double VirtualScreenWidth 29 | { 30 | get { return SystemParameters.VirtualScreenWidth; } 31 | } 32 | 33 | public double VirtualScreenHeight 34 | { 35 | get { return SystemParameters.VirtualScreenHeight; } 36 | } 37 | 38 | public bool IsMaximized 39 | { 40 | get { return WindowState == WindowState.Maximized; } 41 | set 42 | { 43 | if (value) 44 | { 45 | WindowState = WindowState.Maximized; 46 | } 47 | else if (WindowState == WindowState.Maximized) 48 | { 49 | WindowState = WindowState.Normal; 50 | } 51 | } 52 | } 53 | 54 | public double GridSplitterPosition 55 | { 56 | get { return grid.ColumnDefinitions[2].Width.Value; } 57 | set { grid.ColumnDefinitions[2].Width = new GridLength(value, GridUnitType.Pixel); } 58 | } 59 | 60 | private static void TryExecute(ICommand command) 61 | { 62 | if (command.CanExecute(null)) 63 | { 64 | command.Execute(null); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/Resources/ConverterResources.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Presentation/DesignData/MockShellService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Threading.Tasks; 5 | using System.Waf.Foundation; 6 | 7 | using TumblThree.Applications; 8 | using TumblThree.Applications.Auth; 9 | using TumblThree.Applications.Properties; 10 | using TumblThree.Applications.Services; 11 | 12 | namespace TumblThree.Presentation.DesignData 13 | { 14 | public class MockShellService : Model, IShellService 15 | { 16 | public MockShellService() 17 | { 18 | Settings = new AppSettings(); 19 | } 20 | 21 | public AppSettings Settings { get; set; } 22 | 23 | public object ShellView { get; set; } 24 | 25 | public object ContentView { get; set; } 26 | 27 | public object DetailsView { get; set; } 28 | 29 | public object QueueView { get; set; } 30 | 31 | public object CrawlerView { get; set; } 32 | 33 | public IReadOnlyCollection TasksToCompleteBeforeShutdown { get; set; } 34 | 35 | public bool IsApplicationBusy { get; set; } 36 | 37 | public event CancelEventHandler Closing; 38 | 39 | public void ShowError(Exception exception, string displayMessage) 40 | { 41 | } 42 | 43 | public void ShowDetailsView() 44 | { 45 | } 46 | 47 | public void ShowQueueView() 48 | { 49 | } 50 | 51 | public void UpdateDetailsView() 52 | { 53 | } 54 | 55 | public void AddTaskToCompleteBeforeShutdown(Task task) 56 | { 57 | } 58 | 59 | public ClipboardMonitor ClipboardMonitor { get; set; } 60 | 61 | public OAuthManager OAuthManager { get; set; } 62 | 63 | public IDisposable SetApplicationBusy() 64 | { 65 | return null; 66 | } 67 | 68 | public void ShowSettingsView() 69 | { 70 | } 71 | 72 | public void ShowAboutView() 73 | { 74 | } 75 | 76 | protected virtual void OnClosing(CancelEventArgs e) 77 | { 78 | Closing?.Invoke(this, e); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Applications/Services/ManagerService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.ComponentModel.Composition; 5 | using System.Waf.Foundation; 6 | 7 | using TumblThree.Domain.Models; 8 | 9 | namespace TumblThree.Applications.Services 10 | { 11 | [Export, Export(typeof(IManagerService))] 12 | internal class ManagerService : Model, IManagerService 13 | { 14 | private readonly ObservableCollection blogFiles; 15 | private readonly IList databases; 16 | private readonly object checkFilesLock = new object(); 17 | private readonly object databasesLock = new object(); 18 | 19 | [ImportingConstructor] 20 | public ManagerService() 21 | { 22 | blogFiles = new ObservableCollection(); 23 | databases = new List(); 24 | } 25 | 26 | public ObservableCollection BlogFiles 27 | { 28 | get { return blogFiles; } 29 | } 30 | 31 | public IEnumerable Databases 32 | { 33 | get { return databases; } 34 | } 35 | 36 | public bool CheckIfFileExistsInDB(string url) 37 | { 38 | lock (checkFilesLock) 39 | { 40 | foreach (IFiles db in databases) 41 | { 42 | if (db.CheckIfFileExistsInDB(url)) 43 | return true; 44 | } 45 | return false; 46 | } 47 | } 48 | 49 | public void RemoveDatabase(IFiles database) 50 | { 51 | lock (databasesLock) 52 | { 53 | databases.Remove(database); 54 | } 55 | } 56 | 57 | public void AddDatabase(IFiles database) 58 | { 59 | lock (databasesLock) 60 | { 61 | databases.Add(database); 62 | } 63 | } 64 | 65 | public void ClearDatabases() 66 | { 67 | lock (databasesLock) 68 | { 69 | databases.Clear(); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Presentation/Converters/InvertBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | namespace System.Waf.Presentation.Converters 5 | { 6 | /// 7 | /// Value converter that inverts a boolean value. 8 | /// 9 | [ValueConversion(typeof(bool), typeof(bool))] 10 | public class InvertBooleanConverter : IValueConverter 11 | { 12 | private static readonly InvertBooleanConverter defaultInstance = new InvertBooleanConverter(); 13 | 14 | /// 15 | /// Gets the default instance of this converter. 16 | /// 17 | public static InvertBooleanConverter Default { get { return defaultInstance; } } 18 | 19 | 20 | /// 21 | /// Converts a boolean value into the inverted value. 22 | /// 23 | /// The boolean value to invert. 24 | /// The type of the binding target property. This parameter will be ignored. 25 | /// The converter parameter to use. This parameter will be ignored. 26 | /// The culture to use in the converter. 27 | /// The inverter boolean value. 28 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 29 | { 30 | return !(bool)value; 31 | } 32 | 33 | /// 34 | /// Converts a boolean value into the inverted value. 35 | /// 36 | /// The boolean value to invert. 37 | /// The type to convert to. This parameter will be ignored. 38 | /// The converter parameter to use. This parameter will be ignored. 39 | /// The culture to use in the converter. 40 | /// The inverter boolean value. 41 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 42 | { 43 | return !(bool)value; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/TumblThree/TumblThree.Domain/Models/UrlValidator.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.Linq; 3 | 4 | namespace TumblThree.Domain.Models 5 | { 6 | [Export(typeof(IUrlValidator))] 7 | [PartCreationPolicy(CreationPolicy.Shared)] 8 | public class UrlValidator : IUrlValidator 9 | { 10 | public bool IsValidTumblrUrl(string url) 11 | { 12 | return url != null && url.Length > 18 && url.Contains(".tumblr.com") && !url.Contains("www.tumblr.com") && !url.Any(char.IsWhiteSpace) && 13 | (url.StartsWith("http://", true, null) || url.StartsWith("https://", true, null)); 14 | } 15 | 16 | public bool IsValidTumblrHiddenUrl(string url) 17 | { 18 | return url != null && url.Length > 38 && url.Contains("www.tumblr.com/dashboard/blog/") && !url.Any(char.IsWhiteSpace) && 19 | (url.StartsWith("http://", true, null) || url.StartsWith("https://", true, null)); 20 | } 21 | 22 | public bool IsValidTumblrLikedByUrl(string url) 23 | { 24 | return url != null && url.Length > 31 && url.Contains("www.tumblr.com/liked/by/") && !url.Any(char.IsWhiteSpace) && 25 | (url.StartsWith("http://", true, null) || url.StartsWith("https://", true, null)); 26 | } 27 | 28 | public bool IsValidTumblrSearchUrl(string url) 29 | { 30 | return url != null && url.Length > 29 && url.Contains("www.tumblr.com/search/") && !url.Any(char.IsWhiteSpace) && 31 | (url.StartsWith("http://", true, null) || url.StartsWith("https://", true, null)); 32 | } 33 | 34 | public bool IsValidTumblrTagSearchUrl(string url) 35 | { 36 | return url != null && url.Length > 29 && url.Contains("www.tumblr.com/tagged/") && !url.Any(char.IsWhiteSpace) && 37 | (url.StartsWith("http://", true, null) || url.StartsWith("https://", true, null)); 38 | } 39 | 40 | public string AddHttpsProtocol(string url) 41 | { 42 | if (url == null) 43 | return string.Empty; 44 | if (!url.Contains("http")) 45 | return "https://" + url; 46 | return url; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/WpfApplicationFramework/WpfApplicationFramework/Foundation/ReadOnlyObservableList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Collections.Specialized; 3 | using System.ComponentModel; 4 | 5 | namespace System.Waf.Foundation 6 | { 7 | /// 8 | /// Represents a read-only . 9 | /// This class implements the IReadOnlyObservableList interface and provides public CollectionChanged and PropertyChanged events. 10 | /// 11 | /// The type of elements in the collection. 12 | [Serializable] 13 | public class ReadOnlyObservableList : ReadOnlyObservableCollection, IReadOnlyObservableList 14 | { 15 | /// 16 | /// Initializes a new instance of the 17 | /// class that serves as a wrapper around the specified . 18 | /// 19 | /// 20 | /// The with which to 21 | /// create this instance of the 22 | /// class. 23 | /// list is null. 24 | public ReadOnlyObservableList(ObservableCollection list) 25 | : base(list) 26 | { 27 | } 28 | 29 | 30 | /// 31 | /// Occurs when the collection changes. 32 | /// 33 | public new event NotifyCollectionChangedEventHandler CollectionChanged 34 | { 35 | add { base.CollectionChanged += value; } 36 | remove { base.CollectionChanged -= value; } 37 | } 38 | 39 | /// 40 | /// Occurs when a property value changes. 41 | /// 42 | public new event PropertyChangedEventHandler PropertyChanged 43 | { 44 | add { base.PropertyChanged += value; } 45 | remove { base.PropertyChanged -= value; } 46 | } 47 | } 48 | } 49 | --------------------------------------------------------------------------------