Initial Commit
This commit is contained in:
commit
44a89ad589
21 changed files with 477 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
.idea/
|
||||
*.user
|
||||
16
FreeTubeSyncer.sln
Normal file
16
FreeTubeSyncer.sln
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeTubeSyncer", "FreeTubeSyncer\FreeTubeSyncer.csproj", "{B32732C0-EEA7-4149-90D0-933E4DACE3B0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B32732C0-EEA7-4149-90D0-933E4DACE3B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B32732C0-EEA7-4149-90D0-933E4DACE3B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B32732C0-EEA7-4149-90D0-933E4DACE3B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B32732C0-EEA7-4149-90D0-933E4DACE3B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
25
FreeTubeSyncer/App.axaml
Normal file
25
FreeTubeSyncer/App.axaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="FreeTubeSyncer.App"
|
||||
RequestedThemeVariant="Default">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
</Application.Styles>
|
||||
|
||||
<TrayIcon.Icons>
|
||||
<TrayIcons>
|
||||
<TrayIcon Icon="/Assets/freetube.png"
|
||||
ToolTipText="FreeTube Syncer">
|
||||
<TrayIcon.Menu>
|
||||
<NativeMenu>
|
||||
<NativeMenuItem Header="Show Settings"/>
|
||||
<NativeMenuItemSeparator/>
|
||||
<NativeMenuItem Header="Quit"/>
|
||||
</NativeMenu>
|
||||
</TrayIcon.Menu>
|
||||
</TrayIcon>
|
||||
</TrayIcons>
|
||||
</TrayIcon.Icons>
|
||||
</Application>
|
||||
53
FreeTubeSyncer/App.axaml.cs
Normal file
53
FreeTubeSyncer/App.axaml.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using FreeTubeSyncer.Library;
|
||||
using FreeTubeSyncer.Models.DatabaseModels;
|
||||
|
||||
namespace FreeTubeSyncer;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
private DBSyncWatcher _watcher;
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
//desktop.MainWindow = new MainWindow();
|
||||
var path = "";
|
||||
if (OperatingSystem.IsWindows())
|
||||
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FreeTube");
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config",
|
||||
"FreeTube");
|
||||
if (!Path.Exists(path))
|
||||
{
|
||||
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".var", "app", "io.freetubeapp.FreeTube", "config",
|
||||
"FreeTube");
|
||||
if (!Path.Exists(path))
|
||||
Console.WriteLine("Failed to find Path for FreeTube!");
|
||||
}
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FreeTube");
|
||||
|
||||
_watcher = new DBSyncWatcher(path);
|
||||
_watcher.WatchFiles.Add("history.db", typeof(History));
|
||||
_watcher.WatchFiles.Add("playlist.db", typeof(Playlist));
|
||||
_watcher.WatchFiles.Add("profiles.db", typeof(Profile));
|
||||
_watcher.WatchFiles.Add("search-history.db", typeof(SearchHistory));
|
||||
_watcher.WatchFiles.Add("settings.db", typeof(Setting));
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
}
|
||||
BIN
FreeTubeSyncer/Assets/awaiting_sync.png
Normal file
BIN
FreeTubeSyncer/Assets/awaiting_sync.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
FreeTubeSyncer/Assets/freetube.png
Normal file
BIN
FreeTubeSyncer/Assets/freetube.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
FreeTubeSyncer/Assets/sync_complete.png
Normal file
BIN
FreeTubeSyncer/Assets/sync_complete.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
34
FreeTubeSyncer/FreeTubeSyncer.csproj
Normal file
34
FreeTubeSyncer/FreeTubeSyncer.csproj
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.3.2"/>
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.3.2"/>
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.2"/>
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.2"/>
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.2"/>
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.2">
|
||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Assets\" />
|
||||
<Folder Include="Views\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\freetube.png" />
|
||||
<AvaloniaXaml Include="Assets\freetube.png" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
70
FreeTubeSyncer/Library/DBSyncWatcher.cs
Normal file
70
FreeTubeSyncer/Library/DBSyncWatcher.cs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FreeTubeSyncer.Library;
|
||||
|
||||
public class DBSyncWatcher
|
||||
{
|
||||
private FileSystemWatcher _watcher;
|
||||
public Dictionary<string, Type> WatchFiles { get; set; } = [];
|
||||
|
||||
public delegate void DatabaseChange(string db, object value);
|
||||
public event DatabaseChange OnDatabaseChange;
|
||||
|
||||
public DBSyncWatcher(string path)
|
||||
{
|
||||
_watcher = new FileSystemWatcher(path);
|
||||
_watcher.NotifyFilter = NotifyFilters.LastWrite |
|
||||
NotifyFilters.CreationTime;
|
||||
|
||||
_watcher.Changed += HandleChanged;
|
||||
_watcher.Created += HandleCreated;
|
||||
_watcher.Error += HandleError;
|
||||
|
||||
_watcher.Filter = "*.db";
|
||||
_watcher.IncludeSubdirectories = true;
|
||||
_watcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
private void HandleChanged(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
if (e.ChangeType != WatcherChangeTypes.Changed) return;
|
||||
|
||||
var dbName = Path.GetFileName(e.FullPath);
|
||||
|
||||
if (!WatchFiles.Keys.Contains(dbName)) return;
|
||||
|
||||
Console.WriteLine("New Change in {0}", dbName);
|
||||
|
||||
var data = File.ReadAllText(e.FullPath);
|
||||
foreach (var line in data.Split('\n'))
|
||||
{
|
||||
var type = WatchFiles[dbName];
|
||||
var item = JsonSerializer.Deserialize(line, type);
|
||||
if (item == null) continue;
|
||||
OnDatabaseChange?.Invoke(dbName, item);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCreated(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
if (e.ChangeType != WatcherChangeTypes.Created) return;
|
||||
var dbName = Path.GetFileName(e.FullPath);
|
||||
if (!WatchFiles.Keys.Contains(dbName)) return;
|
||||
var data = File.ReadAllText(e.FullPath);
|
||||
foreach (var line in data.Split('\n'))
|
||||
{
|
||||
var type = WatchFiles[dbName];
|
||||
var item = JsonSerializer.Deserialize(line, type);
|
||||
if (item == null) continue;
|
||||
OnDatabaseChange?.Invoke(dbName, item);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleError(object sender, ErrorEventArgs e)
|
||||
{
|
||||
Console.WriteLine("Error: {0}\n{1}", e.GetException().Message, e.GetException().StackTrace);
|
||||
}
|
||||
}
|
||||
9
FreeTubeSyncer/MainWindow.axaml
Normal file
9
FreeTubeSyncer/MainWindow.axaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="FreeTubeSyncer.MainWindow"
|
||||
Title="FreeTubeSyncer">
|
||||
Welcome to Avalonia!
|
||||
</Window>
|
||||
11
FreeTubeSyncer/MainWindow.axaml.cs
Normal file
11
FreeTubeSyncer/MainWindow.axaml.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace FreeTubeSyncer;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
23
FreeTubeSyncer/Models/DatabaseModels/History.cs
Normal file
23
FreeTubeSyncer/Models/DatabaseModels/History.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace FreeTubeSyncer.Models.DatabaseModels;
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class History
|
||||
{
|
||||
public string _id { get; set; } = string.Empty;
|
||||
public string videoId { get; set; } = string.Empty;
|
||||
public string title { get; set; } = string.Empty;
|
||||
public string author { get; set; } = string.Empty;
|
||||
public string authorId { get; set; } = string.Empty;
|
||||
public long published { get; set; }
|
||||
public string description { get; set; } = string.Empty;
|
||||
public long viewCount { get; set; }
|
||||
public long lengthSeconds { get; set; }
|
||||
public float watchProgress { get; set; }
|
||||
public long timeWatched { get; set; }
|
||||
public bool isLive { get; set; }
|
||||
public string type { get; set; } = string.Empty;
|
||||
public string lastViewedPlaylistType { get; set; } = string.Empty;
|
||||
public string? lastViewedPlaylistItemId { get; set; }
|
||||
}
|
||||
15
FreeTubeSyncer/Models/DatabaseModels/Playlist.cs
Normal file
15
FreeTubeSyncer/Models/DatabaseModels/Playlist.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace FreeTubeSyncer.Models.DatabaseModels;
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class Playlist
|
||||
{
|
||||
public string _id { get; set; } = string.Empty;
|
||||
public string playlistName { get; set; } = string.Empty;
|
||||
public bool @protected { get; set; }
|
||||
public List<Video> videos { get; set; } = [];
|
||||
public long createdAt { get; set; }
|
||||
public long lastUpdatedAt { get; set; }
|
||||
}
|
||||
14
FreeTubeSyncer/Models/DatabaseModels/Profile.cs
Normal file
14
FreeTubeSyncer/Models/DatabaseModels/Profile.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace FreeTubeSyncer.Models.DatabaseModels;
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class Profile
|
||||
{
|
||||
public string _id { get; set; } = string.Empty;
|
||||
public string name { get; set; } = string.Empty;
|
||||
public string bgColor { get; set; } = string.Empty;
|
||||
public string textColor { get; set; } = string.Empty;
|
||||
public List<Subscription> subscriptions { get; set; } = [];
|
||||
}
|
||||
10
FreeTubeSyncer/Models/DatabaseModels/SearchHistory.cs
Normal file
10
FreeTubeSyncer/Models/DatabaseModels/SearchHistory.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace FreeTubeSyncer.Models.DatabaseModels;
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class SearchHistory
|
||||
{
|
||||
public string _id { get; set; } = string.Empty;
|
||||
public long lastUpdatedAt { get; set; }
|
||||
}
|
||||
21
FreeTubeSyncer/Models/DatabaseModels/Setting.cs
Normal file
21
FreeTubeSyncer/Models/DatabaseModels/Setting.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FreeTubeSyncer.Models.DatabaseModels;
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class Setting
|
||||
{
|
||||
#pragma warning disable CS8618
|
||||
public string _id { get; set; } = string.Empty;
|
||||
public string? ValueJson { get; set; }
|
||||
#pragma warning restore CS8618
|
||||
|
||||
public object Value
|
||||
{
|
||||
#pragma warning disable CS8603
|
||||
get => string.IsNullOrEmpty(ValueJson) ? null : JsonSerializer.Deserialize<object>(ValueJson);
|
||||
#pragma warning restore CS8603
|
||||
set => ValueJson = JsonSerializer.Serialize(value);
|
||||
}
|
||||
}
|
||||
11
FreeTubeSyncer/Models/DatabaseModels/Subscription.cs
Normal file
11
FreeTubeSyncer/Models/DatabaseModels/Subscription.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace FreeTubeSyncer.Models.DatabaseModels;
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class Subscription
|
||||
{
|
||||
public required string id { get; set; }
|
||||
public required string name { get; set; }
|
||||
public string? thumbnail { get; set; }
|
||||
}
|
||||
17
FreeTubeSyncer/Models/DatabaseModels/Video.cs
Normal file
17
FreeTubeSyncer/Models/DatabaseModels/Video.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace FreeTubeSyncer.Models.DatabaseModels;
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class Video
|
||||
{
|
||||
public string videoId { get; set; } = string.Empty;
|
||||
public string title { get; set; } = string.Empty;
|
||||
public string author { get; set; } = string.Empty;
|
||||
public string authorId { get; set; } = string.Empty;
|
||||
public string lengthSeconds { get; set; } = string.Empty;
|
||||
public long pubished { get; set; }
|
||||
public long timeAdded { get; set; }
|
||||
public string playlistItemId { get; set; } = string.Empty;
|
||||
public string type { get; set; } = string.Empty;
|
||||
}
|
||||
21
FreeTubeSyncer/Program.cs
Normal file
21
FreeTubeSyncer/Program.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using Avalonia;
|
||||
using System;
|
||||
|
||||
namespace FreeTubeSyncer;
|
||||
|
||||
class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.WithInterFont()
|
||||
.LogToTrace();
|
||||
}
|
||||
102
FreeTubeSyncer/REST/RestSync.cs
Normal file
102
FreeTubeSyncer/REST/RestSync.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FreeTubeSyncer.Library;
|
||||
using FreeTubeSyncer.Models.DatabaseModels;
|
||||
using RestSharp;
|
||||
|
||||
namespace FreeTubeSyncer.REST;
|
||||
|
||||
public class RestSync
|
||||
{
|
||||
private List<History> _history = [];
|
||||
private List<Playlist> _playlist = [];
|
||||
private List<Profile> _profile = [];
|
||||
private List<SearchHistory> _searchHistory = [];
|
||||
private List<Setting> _setting = [];
|
||||
|
||||
private bool _dirtyHistory = false;
|
||||
private bool _dirtyPlaylist = false;
|
||||
private bool _dirtyProfile = false;
|
||||
private bool _dirtySearchHistory = false;
|
||||
private bool _dirtySetting = false;
|
||||
private RestClient _client;
|
||||
|
||||
public RestSync(DBSyncWatcher watcher)
|
||||
{
|
||||
watcher.OnDatabaseChange += HandleDatabaseChange;
|
||||
var options = new RestClientOptions
|
||||
{
|
||||
BaseUrl = new Uri("http://localhost:5183/")
|
||||
};
|
||||
_client = new RestClient(options);
|
||||
PrePopulate();
|
||||
CheckCanSync();
|
||||
}
|
||||
|
||||
private async Task PrePopulate()
|
||||
{
|
||||
var resHistory = await _client.GetAsync<List<History>>("/history");
|
||||
_history = resHistory;
|
||||
var resPlaylist = await _client.GetAsync<List<Playlist>>("/playlist");
|
||||
_playlist = resPlaylist;
|
||||
var resProfile = await _client.GetAsync<List<Profile>>("/profile");
|
||||
_profile = resProfile;
|
||||
var resSearchHistory = await _client.GetAsync<List<SearchHistory>>("/searchHistory");
|
||||
_searchHistory = resSearchHistory;
|
||||
var resSetting = await _client.GetAsync<List<Setting>>("/setting");
|
||||
_setting = resSetting;
|
||||
}
|
||||
|
||||
private void CheckCanSync()
|
||||
{
|
||||
if (Process.GetProcessesByName("FreeTube").ToList().Count > 0)
|
||||
{
|
||||
Console.WriteLine("FreeTube is running, awaiting till we can sync.");
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDatabaseChange(string dbName, object obj)
|
||||
{
|
||||
switch (dbName)
|
||||
{
|
||||
case "history.db":
|
||||
var history = (History?)obj;
|
||||
if (history == null) return;
|
||||
if (_history.Any(x => x._id == history._id)) return;
|
||||
_history.Add(history);
|
||||
_dirtyHistory = true;
|
||||
break;
|
||||
case "playlist.db":
|
||||
var playlist = (Playlist?)obj;
|
||||
if (playlist == null) return;
|
||||
if (_playlist.Any(x => x._id == playlist._id)) return;
|
||||
_playlist.Add(playlist);
|
||||
_dirtyPlaylist = true;
|
||||
break;
|
||||
case "profile.db":
|
||||
var profile = (Profile?)obj;
|
||||
if (profile == null) return;
|
||||
if (_profile.Any(x => x._id == profile._id)) return;
|
||||
_profile.Add(profile);
|
||||
_dirtyProfile = true;
|
||||
break;
|
||||
case "search.db":
|
||||
var search = (SearchHistory?)obj;
|
||||
if (search == null) return;
|
||||
if (_searchHistory.Any(x => x._id == search._id)) return;
|
||||
_searchHistory.Add(search);
|
||||
_dirtySearchHistory = true;
|
||||
break;
|
||||
case "setting.db":
|
||||
var setting = (Setting?)obj;
|
||||
if (setting == null) return;
|
||||
if (_setting.Any(x => x._id == setting._id)) return;
|
||||
_setting.Add(setting);
|
||||
_dirtySetting = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
FreeTubeSyncer/app.manifest
Normal file
18
FreeTubeSyncer/app.manifest
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="FreeTubeSyncer.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
Loading…
Add table
Add a link
Reference in a new issue