Compare commits

...

6 commits

Author SHA1 Message Date
8e11008d58 Updated Migrations
Updated Migrations to handle change of Int to Long (SQLite still uses
integer field, but better safe if using something other then SQLite)
Changed Primary Key for Video from VideoId to PlaylistItemId.
2025-07-19 12:47:24 -05:00
6970b792eb Updated Video.cs
Removed videoId as Key, and use playlistItemId as Key, as this will be
unique to each playlist, and will not conflict with videos being on more
then one playlist.
2025-07-19 12:46:14 -05:00
aa2b694d70 Updated Git Ignore
Added SQLite tracking files to ignore.
2025-07-19 12:44:56 -05:00
a61362e9b5 Updated Playlist, SearchHistory and Video
Changed all ints to longs for field datatypes dealing with Unix
timestamp.
2025-07-19 12:42:26 -05:00
2e27078443 Updated SearchHistoryEndpoints.cs
Fixed wrong Model for SearchHistory, was using Regular History class,
instead of SearchHistory class.
2025-07-19 12:40:00 -05:00
15d949d7e1 Updated DataContext.cs
Added Navigation AutoInclude() for Profile subscriptions, and Playlist
videos.
2025-07-19 12:38:36 -05:00
11 changed files with 592 additions and 24 deletions

2
.gitignore vendored
View file

@ -5,3 +5,5 @@ obj/
riderModule.iml
/_ReSharper.Caches/
FreeTubeSync.db
FreeTubeSync.db-wal
FreeTubeSync.db-shm

View file

@ -25,6 +25,20 @@ public class DataContext : DbContext
.Property(s => s.ValueJson)
.HasColumnName("Value")
.IsRequired();
modelBuilder.Entity<Profile>()
.ToTable("Profiles")
.HasKey(s => s._id);
modelBuilder.Entity<Profile>()
.Navigation(e => e.subscriptions).AutoInclude();
modelBuilder.Entity<Playlist>()
.ToTable("Playlists")
.HasKey(s => s._id);
modelBuilder.Entity<Playlist>()
.Navigation(e => e.videos).AutoInclude();
}
public DbSet<History> Histories { get; set; }

View file

@ -8,13 +8,13 @@ public static class SearchHistoryEndpoint
{
var group = app.MapGroup("searchHistory");
group.MapGet("/", async (IRepository<History> repository, CancellationToken ct) =>
group.MapGet("/", async (IRepository<SearchHistory> repository, CancellationToken ct) =>
{
var result = await repository.GetAllAsync(ct);
return Results.Ok(result);
});
group.MapPost("/", async (IRepository<History> repository, CancellationToken ct, History history) =>
group.MapPost("/", async (IRepository<SearchHistory> repository, CancellationToken ct, SearchHistory history) =>
{
var result = await repository.GetByIdAsync(history._id, ct);
if (result != null)
@ -24,7 +24,7 @@ public static class SearchHistoryEndpoint
return Results.Ok();
});
group.MapDelete("/{id}", async (IRepository<History> repository, CancellationToken ct, string id) =>
group.MapDelete("/{id}", async (IRepository<SearchHistory> repository, CancellationToken ct, string id) =>
{
var result = await repository.GetByIdAsync(id, ct);
if (result == null) return Results.NotFound();

View file

@ -0,0 +1,247 @@
// <auto-generated />
using FreeTubeSync.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace FreeTubeSync.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20250719172349_UpdateIntToLong")]
partial class UpdateIntToLong
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.7");
modelBuilder.Entity("FreeTubeSync.Model.History", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<string>("author")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("authorId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("isLive")
.HasColumnType("INTEGER");
b.Property<string>("lastViewedPlaylistItemId")
.HasColumnType("TEXT");
b.Property<string>("lastViewedPlaylistType")
.IsRequired()
.HasColumnType("TEXT");
b.Property<long>("lengthSeconds")
.HasColumnType("INTEGER");
b.Property<long>("published")
.HasColumnType("INTEGER");
b.Property<long>("timeWatched")
.HasColumnType("INTEGER");
b.Property<string>("title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("type")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("videoId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<long>("viewCount")
.HasColumnType("INTEGER");
b.Property<float>("watchProgress")
.HasColumnType("REAL");
b.HasKey("_id");
b.ToTable("Histories");
});
modelBuilder.Entity("FreeTubeSync.Model.Playlist", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<long>("createdAt")
.HasColumnType("INTEGER");
b.Property<long>("lastUpdatedAt")
.HasColumnType("INTEGER");
b.Property<string>("playlistName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("protected")
.HasColumnType("INTEGER");
b.HasKey("_id");
b.ToTable("Playlists", (string)null);
});
modelBuilder.Entity("FreeTubeSync.Model.Profile", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<string>("bgColor")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("textColor")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("_id");
b.ToTable("Profiles", (string)null);
});
modelBuilder.Entity("FreeTubeSync.Model.SearchHistory", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<long>("lastUpdatedAt")
.HasColumnType("INTEGER");
b.HasKey("_id");
b.ToTable("SearchHistories");
});
modelBuilder.Entity("FreeTubeSync.Model.Setting", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<string>("ValueJson")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("Value");
b.HasKey("_id");
b.ToTable("Settings", (string)null);
});
modelBuilder.Entity("FreeTubeSync.Model.Subscription", b =>
{
b.Property<string>("id")
.HasColumnType("TEXT");
b.Property<string>("Profile_id")
.HasColumnType("TEXT");
b.Property<string>("name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("thumbnail")
.HasColumnType("TEXT");
b.HasKey("id");
b.HasIndex("Profile_id");
b.ToTable("Subscriptions");
});
modelBuilder.Entity("FreeTubeSync.Model.Video", b =>
{
b.Property<string>("videoId")
.HasColumnType("TEXT");
b.Property<string>("Playlist_id")
.HasColumnType("TEXT");
b.Property<string>("author")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("authorId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("lengthSeconds")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("playlistItemId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<long>("pubished")
.HasColumnType("INTEGER");
b.Property<long>("timeAdded")
.HasColumnType("INTEGER");
b.Property<string>("title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("type")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("videoId");
b.HasIndex("Playlist_id");
b.ToTable("Videos");
});
modelBuilder.Entity("FreeTubeSync.Model.Subscription", b =>
{
b.HasOne("FreeTubeSync.Model.Profile", null)
.WithMany("subscriptions")
.HasForeignKey("Profile_id");
});
modelBuilder.Entity("FreeTubeSync.Model.Video", b =>
{
b.HasOne("FreeTubeSync.Model.Playlist", null)
.WithMany("videos")
.HasForeignKey("Playlist_id");
});
modelBuilder.Entity("FreeTubeSync.Model.Playlist", b =>
{
b.Navigation("videos");
});
modelBuilder.Entity("FreeTubeSync.Model.Profile", b =>
{
b.Navigation("subscriptions");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace FreeTubeSync.Migrations
{
/// <inheritdoc />
public partial class UpdateIntToLong : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View file

@ -0,0 +1,247 @@
// <auto-generated />
using FreeTubeSync.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace FreeTubeSync.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20250719172939_ChangePrimaryKeyToPlaylistItemId")]
partial class ChangePrimaryKeyToPlaylistItemId
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.7");
modelBuilder.Entity("FreeTubeSync.Model.History", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<string>("author")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("authorId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("isLive")
.HasColumnType("INTEGER");
b.Property<string>("lastViewedPlaylistItemId")
.HasColumnType("TEXT");
b.Property<string>("lastViewedPlaylistType")
.IsRequired()
.HasColumnType("TEXT");
b.Property<long>("lengthSeconds")
.HasColumnType("INTEGER");
b.Property<long>("published")
.HasColumnType("INTEGER");
b.Property<long>("timeWatched")
.HasColumnType("INTEGER");
b.Property<string>("title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("type")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("videoId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<long>("viewCount")
.HasColumnType("INTEGER");
b.Property<float>("watchProgress")
.HasColumnType("REAL");
b.HasKey("_id");
b.ToTable("Histories");
});
modelBuilder.Entity("FreeTubeSync.Model.Playlist", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<long>("createdAt")
.HasColumnType("INTEGER");
b.Property<long>("lastUpdatedAt")
.HasColumnType("INTEGER");
b.Property<string>("playlistName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("protected")
.HasColumnType("INTEGER");
b.HasKey("_id");
b.ToTable("Playlists", (string)null);
});
modelBuilder.Entity("FreeTubeSync.Model.Profile", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<string>("bgColor")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("textColor")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("_id");
b.ToTable("Profiles", (string)null);
});
modelBuilder.Entity("FreeTubeSync.Model.SearchHistory", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<long>("lastUpdatedAt")
.HasColumnType("INTEGER");
b.HasKey("_id");
b.ToTable("SearchHistories");
});
modelBuilder.Entity("FreeTubeSync.Model.Setting", b =>
{
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<string>("ValueJson")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("Value");
b.HasKey("_id");
b.ToTable("Settings", (string)null);
});
modelBuilder.Entity("FreeTubeSync.Model.Subscription", b =>
{
b.Property<string>("id")
.HasColumnType("TEXT");
b.Property<string>("Profile_id")
.HasColumnType("TEXT");
b.Property<string>("name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("thumbnail")
.HasColumnType("TEXT");
b.HasKey("id");
b.HasIndex("Profile_id");
b.ToTable("Subscriptions");
});
modelBuilder.Entity("FreeTubeSync.Model.Video", b =>
{
b.Property<string>("playlistItemId")
.HasColumnType("TEXT");
b.Property<string>("Playlist_id")
.HasColumnType("TEXT");
b.Property<string>("author")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("authorId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("lengthSeconds")
.IsRequired()
.HasColumnType("TEXT");
b.Property<long>("pubished")
.HasColumnType("INTEGER");
b.Property<long>("timeAdded")
.HasColumnType("INTEGER");
b.Property<string>("title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("type")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("videoId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("playlistItemId");
b.HasIndex("Playlist_id");
b.ToTable("Videos");
});
modelBuilder.Entity("FreeTubeSync.Model.Subscription", b =>
{
b.HasOne("FreeTubeSync.Model.Profile", null)
.WithMany("subscriptions")
.HasForeignKey("Profile_id");
});
modelBuilder.Entity("FreeTubeSync.Model.Video", b =>
{
b.HasOne("FreeTubeSync.Model.Playlist", null)
.WithMany("videos")
.HasForeignKey("Playlist_id");
});
modelBuilder.Entity("FreeTubeSync.Model.Playlist", b =>
{
b.Navigation("videos");
});
modelBuilder.Entity("FreeTubeSync.Model.Profile", b =>
{
b.Navigation("subscriptions");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace FreeTubeSync.Migrations
{
/// <inheritdoc />
public partial class ChangePrimaryKeyToPlaylistItemId : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_Videos",
table: "Videos");
migrationBuilder.AddPrimaryKey(
name: "PK_Videos",
table: "Videos",
column: "playlistItemId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_Videos",
table: "Videos");
migrationBuilder.AddPrimaryKey(
name: "PK_Videos",
table: "Videos",
column: "videoId");
}
}
}

View file

@ -1,5 +1,4 @@
// <auto-generated />
using FreeTubeSync.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
@ -81,10 +80,10 @@ namespace FreeTubeSync.Migrations
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<int>("createdAt")
b.Property<long>("createdAt")
.HasColumnType("INTEGER");
b.Property<int>("lastUpdatedAt")
b.Property<long>("lastUpdatedAt")
.HasColumnType("INTEGER");
b.Property<string>("playlistName")
@ -96,7 +95,7 @@ namespace FreeTubeSync.Migrations
b.HasKey("_id");
b.ToTable("Playlists");
b.ToTable("Playlists", (string)null);
});
modelBuilder.Entity("FreeTubeSync.Model.Profile", b =>
@ -118,7 +117,7 @@ namespace FreeTubeSync.Migrations
b.HasKey("_id");
b.ToTable("Profiles");
b.ToTable("Profiles", (string)null);
});
modelBuilder.Entity("FreeTubeSync.Model.SearchHistory", b =>
@ -126,7 +125,7 @@ namespace FreeTubeSync.Migrations
b.Property<string>("_id")
.HasColumnType("TEXT");
b.Property<int>("lastUpdatedAt")
b.Property<long>("lastUpdatedAt")
.HasColumnType("INTEGER");
b.HasKey("_id");
@ -173,7 +172,7 @@ namespace FreeTubeSync.Migrations
modelBuilder.Entity("FreeTubeSync.Model.Video", b =>
{
b.Property<string>("videoId")
b.Property<string>("playlistItemId")
.HasColumnType("TEXT");
b.Property<string>("Playlist_id")
@ -191,14 +190,10 @@ namespace FreeTubeSync.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("playlistItemId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("pubished")
b.Property<long>("pubished")
.HasColumnType("INTEGER");
b.Property<int>("timeAdded")
b.Property<long>("timeAdded")
.HasColumnType("INTEGER");
b.Property<string>("title")
@ -209,7 +204,11 @@ namespace FreeTubeSync.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("videoId");
b.Property<string>("videoId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("playlistItemId");
b.HasIndex("Playlist_id");

View file

@ -11,8 +11,8 @@ public class Playlist
public string playlistName { get; set; } = string.Empty;
public bool @protected { get; set; }
public List<Video> videos { get; set; } = [];
public int createdAt { get; set; }
public int lastUpdatedAt { get; set; }
public long createdAt { get; set; }
public long lastUpdatedAt { get; set; }
public void Update(Playlist other)
{

View file

@ -8,7 +8,7 @@ public class SearchHistory
{
[Key]
public string _id { get; set; } = string.Empty;
public int lastUpdatedAt { get; set; }
public long lastUpdatedAt { get; set; }
public void Update(SearchHistory other)
{

View file

@ -1,18 +1,19 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore;
namespace FreeTubeSync.Model;
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class Video
{
[Key] public string videoId { 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 string lengthSeconds { get; set; } = string.Empty;
public int pubished { get; set; }
public int timeAdded { get; set; }
public string playlistItemId { get; set; } = string.Empty;
public long pubished { get; set; }
public long timeAdded { get; set; }
[Key] public string playlistItemId { get; set; } = string.Empty;
public string type { get; set; } = string.Empty;
}