├── Booklet_Blue.ico
├── Resources
├── Filter_64x64.png
├── Info_16x16.png
├── Read_48x48.png
├── Search_64x64.png
├── Stack_64x64.png
├── Unread_48x48.png
├── Update_64x64.png
├── BarChart_64x64.png
├── Comment_64x64.png
├── DarkMode_64x64.png
├── Notepad_64x64.png
├── Settings_64x64.png
├── LightMode_64x64.png
├── folder-open_64x64.png
├── Heart-Filled_48x48.png
└── Heart-Outline_48x48.png
├── UI
├── App.xaml.cs
├── StoryFilterContent.xaml.cs
├── SettingsWindow.xaml.cs
├── StoryDetails.xaml.cs
├── DownloadWindow.xaml.cs
├── GithubAd.xaml.cs
├── UpdateAvailable.xaml
├── UpdateAvailable.xaml.cs
├── FavoritesToggle.xaml.cs
├── GithubAd.xaml
├── FavoritesToggle.xaml
├── RatingControl.xaml
├── RatingControl.xaml.cs
├── StoriesList.xaml.cs
├── StoryViewer.xaml.cs
├── CircularProgressBar.xaml
├── MainWindow.xaml.cs
├── SearchContent.xaml.cs
├── StoryDetails.xaml
├── App.xaml
├── CircularProgressBar.xaml.cs
├── DownloadWindow.xaml
├── StoryFilterContent.xaml
└── StoryViewer.xaml
├── VM
├── Helpers
│ ├── ViewModelBase.cs
│ ├── UrlExtensions.cs
│ ├── LimitedStack.cs
│ ├── JsonConverters.cs
│ ├── CollectionViewHelpers.cs
│ ├── GeneralUtils.cs
│ ├── Converters.cs
│ └── XMLSerializer.cs
├── Literotica
│ ├── NavigationButton.cs
│ ├── SearchResult.cs
│ ├── AuthorGroup.cs
│ ├── Serialization.cs
│ ├── Model.cs
│ └── LiteroticaUtils.cs
├── Bookmark.cs
├── DisplaySettings.cs
└── FilterSettings.cs
├── Properties
├── PublishProfiles
│ └── SingleFileFrameworkDependent.pubxml
├── Resources.Designer.cs
└── Resources.resx
├── LICENSE
├── StoryManager.sln
├── ideas.txt
├── .gitattributes
├── README.md
├── StoryManager.csproj
└── .gitignore
/Booklet_Blue.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Booklet_Blue.ico
--------------------------------------------------------------------------------
/Resources/Filter_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Filter_64x64.png
--------------------------------------------------------------------------------
/Resources/Info_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Info_16x16.png
--------------------------------------------------------------------------------
/Resources/Read_48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Read_48x48.png
--------------------------------------------------------------------------------
/Resources/Search_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Search_64x64.png
--------------------------------------------------------------------------------
/Resources/Stack_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Stack_64x64.png
--------------------------------------------------------------------------------
/Resources/Unread_48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Unread_48x48.png
--------------------------------------------------------------------------------
/Resources/Update_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Update_64x64.png
--------------------------------------------------------------------------------
/Resources/BarChart_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/BarChart_64x64.png
--------------------------------------------------------------------------------
/Resources/Comment_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Comment_64x64.png
--------------------------------------------------------------------------------
/Resources/DarkMode_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/DarkMode_64x64.png
--------------------------------------------------------------------------------
/Resources/Notepad_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Notepad_64x64.png
--------------------------------------------------------------------------------
/Resources/Settings_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Settings_64x64.png
--------------------------------------------------------------------------------
/Resources/LightMode_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/LightMode_64x64.png
--------------------------------------------------------------------------------
/Resources/folder-open_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/folder-open_64x64.png
--------------------------------------------------------------------------------
/Resources/Heart-Filled_48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Heart-Filled_48x48.png
--------------------------------------------------------------------------------
/Resources/Heart-Outline_48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Videogamers0/StoryManager/HEAD/Resources/Heart-Outline_48x48.png
--------------------------------------------------------------------------------
/UI/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 |
8 | namespace StoryManager
9 | {
10 | public partial class App : Application
11 | {
12 |
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/VM/Helpers/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace StoryManager.VM.Helpers
9 | {
10 | public class ViewModelBase : INotifyPropertyChanged
11 | {
12 | public event PropertyChangedEventHandler PropertyChanged;
13 | public virtual void NotifyPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
14 | public void NPC(string propertyName) => NotifyPropertyChanged(propertyName);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Properties/PublishProfiles/SingleFileFrameworkDependent.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | bin\publish\
10 | FileSystem
11 | <_TargetId>Folder
12 | net7.0-windows
13 | false
14 | win-x64
15 | true
16 | false
17 | True
18 |
19 |
--------------------------------------------------------------------------------
/UI/StoryFilterContent.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace StoryManager.UI
17 | {
18 | ///
19 | /// Interaction logic for StoryFilterContent.xaml
20 | ///
21 | public partial class StoryFilterContent : UserControl
22 | {
23 | public StoryFilterContent()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/UI/SettingsWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.WindowsAPICodePack.Dialogs;
2 | using Prism.Commands;
3 | using StoryManager.VM;
4 | using StoryManager.VM.Helpers;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.ComponentModel;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Windows;
12 | using System.Windows.Controls;
13 | using System.Windows.Data;
14 | using System.Windows.Documents;
15 | using System.Windows.Input;
16 | using System.Windows.Media;
17 | using System.Windows.Media.Imaging;
18 | using System.Windows.Shapes;
19 |
20 | namespace StoryManager.UI
21 | {
22 | ///
23 | /// Interaction logic for SettingsWindow.xaml
24 | ///
25 | public partial class SettingsWindow : Window
26 | {
27 | public SettingsWindow(Settings DataContext)
28 | {
29 | InitializeComponent();
30 | this.DataContext = DataContext;
31 | }
32 |
33 | private void Close_Click(object sender, RoutedEventArgs e) => Close();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/UI/StoryDetails.xaml.cs:
--------------------------------------------------------------------------------
1 | using StoryManager.VM.Helpers;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using System.Windows.Controls;
9 | using System.Windows.Data;
10 | using System.Windows.Documents;
11 | using System.Windows.Input;
12 | using System.Windows.Media;
13 | using System.Windows.Media.Imaging;
14 | using System.Windows.Navigation;
15 | using System.Windows.Shapes;
16 |
17 | namespace StoryManager.UI
18 | {
19 | ///
20 | /// Interaction logic for StoryDetails.xaml
21 | ///
22 | public partial class StoryDetails : UserControl
23 | {
24 | public StoryDetails()
25 | {
26 | InitializeComponent();
27 | }
28 |
29 | private void OpenCategoryInBrowser(object sender, RequestNavigateEventArgs e)
30 | {
31 | string FullUrl = $"https://www.literotica.com/c/{e.Uri.ToString()}";
32 | GeneralUtils.OpenUrl(FullUrl, true);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/VM/Helpers/UrlExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Web;
7 |
8 | namespace StoryManager.VM.Helpers
9 | {
10 | #region https://stackoverflow.com/a/12410826
11 | public static class UrlExtensions
12 | {
13 | public static string SetUrlParameter(this string url, string paramName, string value)
14 | {
15 | return new Uri(url).SetParameter(paramName, value).ToString();
16 | }
17 |
18 | public static Uri SetParameter(this Uri url, string paramName, string value)
19 | {
20 | var queryParts = HttpUtility.ParseQueryString(url.Query);
21 | queryParts[paramName] = value;
22 | return new Uri(url.AbsoluteUriExcludingQuery() + '?' + queryParts.ToString());
23 | }
24 |
25 | public static string AbsoluteUriExcludingQuery(this Uri url)
26 | {
27 | return url.AbsoluteUri.Split('?').FirstOrDefault() ?? String.Empty;
28 | }
29 | }
30 | #endregion
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 SlayerDharok
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 |
--------------------------------------------------------------------------------
/StoryManager.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33414.496
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StoryManager", "StoryManager.csproj", "{BF581157-C9F2-4F39-8E22-939DFAEEF038}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {BF581157-C9F2-4F39-8E22-939DFAEEF038}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {BF581157-C9F2-4F39-8E22-939DFAEEF038}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {BF581157-C9F2-4F39-8E22-939DFAEEF038}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {BF581157-C9F2-4F39-8E22-939DFAEEF038}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {C2B9151D-21A2-4E11-B00E-69F4B3B0D907}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/ideas.txt:
--------------------------------------------------------------------------------
1 | Some ideas for future improvements:
2 |
3 | - Setting to auto-mark stories as 'Read' when user reaches the bottom scroll offset
4 | - Additional settings to change sorting?
5 | Sort groupbox: List of options, can drag/drop to re-order
6 | A-Z, Download Date, Authored Date, Last Viewed, Your Rating etc
7 | - Custom bookmarks
8 | Click a button 'Save bookmark' (use the same icon that Literotica uses for bookmarks) to store the current scroll offset as a numbered bookmark for the selected story
9 | Bookmarks are auto-deleted / un-loadable if they were created with a different WebView2 width,
10 | since the width of the viewer dictates what content is visible at a particular vertical scroll offset
11 | - UI for finding stories that are related to the selected story
12 | - Story importer? Must manually fill in the story metadata, and some features would need to be refactored
13 | such as clicking the Title to open story in browser since the base address would be different
14 | Could also have 2-tabbed UI. Tab #1: Literotica. Tab #2: Other
15 | Other tab would be a simplified copy of the code used for the Literotica tab.
16 | - Story filter settings could have a checkbox list of categories to show/hide
--------------------------------------------------------------------------------
/UI/DownloadWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using StoryManager.VM.Helpers;
2 | using StoryManager.VM.Literotica;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows;
9 | using System.Windows.Controls;
10 | using System.Windows.Data;
11 | using System.Windows.Documents;
12 | using System.Windows.Input;
13 | using System.Windows.Media;
14 | using System.Windows.Media.Imaging;
15 | using System.Windows.Navigation;
16 | using System.Windows.Shapes;
17 |
18 | namespace StoryManager.UI
19 | {
20 | ///
21 | /// Interaction logic for DownloadWindow.xaml
22 | ///
23 | public partial class DownloadWindow : Window
24 | {
25 | public DownloadWindow(Downloader DataContext)
26 | {
27 | InitializeComponent();
28 | this.DataContext = DataContext;
29 |
30 | #if NEVER //DEBUG
31 | this.TopStoriesButton.Visibility = Visibility.Visible;
32 | #endif
33 | }
34 |
35 | private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
36 | {
37 | if (sender is Hyperlink hl)
38 | GeneralUtils.OpenUrl(hl.NavigateUri.ToString(), true);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/UI/GithubAd.xaml.cs:
--------------------------------------------------------------------------------
1 | using StoryManager.VM.Helpers;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using System.Windows.Controls;
9 | using System.Windows.Data;
10 | using System.Windows.Documents;
11 | using System.Windows.Input;
12 | using System.Windows.Media;
13 | using System.Windows.Media.Imaging;
14 | using System.Windows.Navigation;
15 | using System.Windows.Shapes;
16 |
17 | namespace StoryManager.UI
18 | {
19 | ///
20 | /// Interaction logic for GithubAd.xaml
21 | ///
22 | public partial class GithubAd : Window
23 | {
24 | public int OpenedCount { get; }
25 |
26 | public GithubAd(int Count)
27 | {
28 | InitializeComponent();
29 |
30 | OpenedCount = Count;
31 |
32 | DataContext = this;
33 | }
34 |
35 | private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
36 | {
37 | if (sender is Hyperlink hl)
38 | GeneralUtils.OpenUrl(hl.NavigateUri.ToString(), false);
39 | }
40 |
41 | private void Close_Click(object sender, RoutedEventArgs e)
42 | {
43 | Close();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/UI/UpdateAvailable.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/UI/UpdateAvailable.xaml.cs:
--------------------------------------------------------------------------------
1 | using Prism.Commands;
2 | using StoryManager.VM.Helpers;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows;
10 | using System.Windows.Controls;
11 | using System.Windows.Data;
12 | using System.Windows.Documents;
13 | using System.Windows.Input;
14 | using System.Windows.Media;
15 | using System.Windows.Media.Imaging;
16 | using System.Windows.Shapes;
17 |
18 | namespace StoryManager.UI
19 | {
20 | ///
21 | /// Interaction logic for UpdateAvailable.xaml
22 | ///
23 | public partial class UpdateAvailable : Window, INotifyPropertyChanged
24 | {
25 | public event PropertyChangedEventHandler PropertyChanged;
26 | public virtual void NotifyPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
27 | public void NPC(string propertyName) => NotifyPropertyChanged(propertyName);
28 |
29 | public Octokit.Release Release { get; }
30 |
31 | public UpdateAvailable(Octokit.Release LatestRelease)
32 | {
33 | InitializeComponent();
34 | Release = LatestRelease;
35 | DataContext = this;
36 | }
37 |
38 | private void Close_Click(object sender, RoutedEventArgs e) => Close();
39 | public DelegateCommand