diff --git a/backend/src/Application/Application.csproj b/backend/src/Application/Application.csproj deleted file mode 100644 index 64eb85d..0000000 --- a/backend/src/Application/Application.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - net9.0 - enable - enable - - - diff --git a/backend/src/Application/Services/ItemService.cs b/backend/src/Application/Services/ItemService.cs deleted file mode 100644 index ac5e840..0000000 --- a/backend/src/Application/Services/ItemService.cs +++ /dev/null @@ -1 +0,0 @@ -namespace JellyGlass.Application.Services; \ No newline at end of file diff --git a/backend/src/Controllers/LibraryController.cs b/backend/src/Controllers/LibraryController.cs new file mode 100644 index 0000000..f3fc142 --- /dev/null +++ b/backend/src/Controllers/LibraryController.cs @@ -0,0 +1,51 @@ +using JellyGlass.Models; +using JellyGlass.Services; +using Microsoft.AspNetCore.Mvc; + +namespace JellyGlass.Controllers; + +[ApiController] +[Route("/api/[controller]")] +public class LibraryController : ControllerBase +{ + private ILogger _logger; + private ILibraryService _service; + + public LibraryController(ILogger logger, ILibraryService service) + { + _logger = logger; + _service = service; + } + + [HttpGet()] + public async Task GetLibrares() + { + var libraries = await _service.GetLibraries(); + + return Ok(libraries); + } + + [HttpGet("{libraryName}")] + public async Task GetLibraryItems([FromRoute] string libraryName) + { + throw new NotImplementedException(); + } + + // [HttpGet("{libraryName}/Item/{itemName}")] + // public async Task GetLibraryItem([FromRoute] string libraryName, string itemName) + // { + + // } + + // [HttpGet("TvShows/{seriesName}")] + // public async Task GetSeasonsForTvSeries([FromRoute] string seriesName) + // { + + // } + + // [HttpGet("TvShows/{seriesName}/Season/{seasonName}")] + // public async Task GetEpisodesForTvSeriesSeason([FromRoute] string seriesName, string seasonName) + // { + + // } +} \ No newline at end of file diff --git a/backend/src/Application/Services/LibraryService.cs b/backend/src/Controllers/MoviesController.cs similarity index 100% rename from backend/src/Application/Services/LibraryService.cs rename to backend/src/Controllers/MoviesController.cs diff --git a/backend/src/Application/Services/ServerService.cs b/backend/src/Controllers/TvShowsController.cs similarity index 100% rename from backend/src/Application/Services/ServerService.cs rename to backend/src/Controllers/TvShowsController.cs diff --git a/backend/src/Core/Core.csproj b/backend/src/Core/Core.csproj deleted file mode 100644 index 125f4c9..0000000 --- a/backend/src/Core/Core.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - net9.0 - enable - enable - - - diff --git a/backend/src/Core/Entities/Item.cs b/backend/src/Core/Entities/Item.cs deleted file mode 100644 index 0352276..0000000 --- a/backend/src/Core/Entities/Item.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace JellyGlass.Core.Entities; - -public class Item -{ - public string ID { get; set; } - public string Name { get; set; } - public Uri ThumbnailUrl { get; set; } - public Uri Url { get; set; } -} \ No newline at end of file diff --git a/backend/src/Core/Entities/Library.cs b/backend/src/Core/Entities/Library.cs deleted file mode 100644 index cf0ee35..0000000 --- a/backend/src/Core/Entities/Library.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace JellyGlass.Core.Entities; - -public class Library -{ - public string ID { get; set; } - public string Name { get; set; } - public Uri ThumbnailUrl { get; set; } -} \ No newline at end of file diff --git a/backend/src/Core/Entities/Server.cs b/backend/src/Core/Entities/Server.cs deleted file mode 100644 index 91181d0..0000000 --- a/backend/src/Core/Entities/Server.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace JellyGlass.Core.Entities; - -public class Server -{ - public string Owner { get; set; } - public Uri Url { get; set; } -} \ No newline at end of file diff --git a/backend/src/Core/Interfaces/IItemRepository.cs b/backend/src/Core/Interfaces/IItemRepository.cs deleted file mode 100644 index 3502a94..0000000 --- a/backend/src/Core/Interfaces/IItemRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using JellyGlass.Core.Entities; - -namespace JellyGlass.Core.Interfaces; - -public interface IItemRepository -{ - public Task GetItemsFromLibrary(string libraryId); -} \ No newline at end of file diff --git a/backend/src/Core/Interfaces/IItemService.cs b/backend/src/Core/Interfaces/IItemService.cs deleted file mode 100644 index 3d32dbb..0000000 --- a/backend/src/Core/Interfaces/IItemService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using JellyGlass.Core.Entities; - -namespace JellyGlass.Core.Interfaces; - -public interface IItemService -{ - public Task GetItemsFromLibrary(string libraryId); -} \ No newline at end of file diff --git a/backend/src/Core/Interfaces/ILibraryRepository.cs b/backend/src/Core/Interfaces/ILibraryRepository.cs deleted file mode 100644 index 1c47580..0000000 --- a/backend/src/Core/Interfaces/ILibraryRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using JellyGlass.Core.Entities; - -namespace JellyGlass.Core.Interfaces; - -public interface ILibraryRepository -{ - public Task GetLibraries(); -} \ No newline at end of file diff --git a/backend/src/Core/Interfaces/ILibraryService.cs b/backend/src/Core/Interfaces/ILibraryService.cs deleted file mode 100644 index b775085..0000000 --- a/backend/src/Core/Interfaces/ILibraryService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using JellyGlass.Core.Entities; - -namespace JellyGlass.Core.Interfaces; - -public interface ILibraryService -{ - public Task GetLibraries(); -} \ No newline at end of file diff --git a/backend/src/Core/Interfaces/IServerService.cs b/backend/src/Core/Interfaces/IServerService.cs deleted file mode 100644 index 238da9c..0000000 --- a/backend/src/Core/Interfaces/IServerService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using JellyGlass.Core.Entities; - -namespace JellyGlass.Core.Interfaces; - -public interface IServerService -{ - public Task GetServers(); -} \ No newline at end of file diff --git a/backend/src/Exceptions/JellyfinApiClientExceptions.cs b/backend/src/Exceptions/JellyfinApiClientExceptions.cs new file mode 100644 index 0000000..d979004 --- /dev/null +++ b/backend/src/Exceptions/JellyfinApiClientExceptions.cs @@ -0,0 +1,9 @@ +namespace JellyGlass.Exceptions; + +[Serializable] +public class JellyfinApiClientException : Exception +{ + public JellyfinApiClientException() { } + public JellyfinApiClientException(string message) : base(message) { } + public JellyfinApiClientException(string message, Exception inner) : base(message, inner) { } +} \ No newline at end of file diff --git a/backend/src/Infrastructure/Infrastructure.csproj b/backend/src/Infrastructure/Infrastructure.csproj deleted file mode 100644 index 8a49582..0000000 --- a/backend/src/Infrastructure/Infrastructure.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - net9.0 - enable - enable - - - diff --git a/backend/src/Infrastructure/Repositories/ItemRepository.cs b/backend/src/Infrastructure/Repositories/ItemRepository.cs deleted file mode 100644 index 129e431..0000000 --- a/backend/src/Infrastructure/Repositories/ItemRepository.cs +++ /dev/null @@ -1,4 +0,0 @@ -using JellyGlass.Core.Entities; -using JellyGlass.Core.Interfaces; - -namespace JellyGlass.Infrastructure.Repositories; \ No newline at end of file diff --git a/backend/src/Infrastructure/Repositories/LibraryRepository.cs b/backend/src/Infrastructure/Repositories/LibraryRepository.cs deleted file mode 100644 index 49c02d5..0000000 --- a/backend/src/Infrastructure/Repositories/LibraryRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JellyGlass.Core.Entities; -using JellyGlass.Core.Interfaces; - -namespace JellyGlass.Infrastructure.Repositories; - -public class LibraryRepository : ILibraryRepository -{ - public Task GetLibraries() - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/backend/src/Infrastructure/Repositories/ServerRepository.cs b/backend/src/Infrastructure/Repositories/ServerRepository.cs deleted file mode 100644 index 129e431..0000000 --- a/backend/src/Infrastructure/Repositories/ServerRepository.cs +++ /dev/null @@ -1,4 +0,0 @@ -using JellyGlass.Core.Entities; -using JellyGlass.Core.Interfaces; - -namespace JellyGlass.Infrastructure.Repositories; \ No newline at end of file diff --git a/backend/src/Infrastructure/Services/JellyfinApiClient.cs b/backend/src/Infrastructure/Services/JellyfinApiClient.cs deleted file mode 100644 index 572a1a2..0000000 --- a/backend/src/Infrastructure/Services/JellyfinApiClient.cs +++ /dev/null @@ -1 +0,0 @@ -namespace JellyGlass.Infrastructure.Services; \ No newline at end of file diff --git a/backend/src/JellyGlass-Backend.csproj b/backend/src/JellyGlass-Backend.csproj new file mode 100644 index 0000000..2bc8cc1 --- /dev/null +++ b/backend/src/JellyGlass-Backend.csproj @@ -0,0 +1,18 @@ + + + + net9.0 + enable + enable + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + diff --git a/backend/src/JellyGlass-test.db b/backend/src/JellyGlass-test.db new file mode 100644 index 0000000..0b21577 Binary files /dev/null and b/backend/src/JellyGlass-test.db differ diff --git a/backend/src/JellyGlass.sln b/backend/src/JellyGlass.sln deleted file mode 100644 index 2d83437..0000000 --- a/backend/src/JellyGlass.sln +++ /dev/null @@ -1,40 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi", "WebApi\WebApi.csproj", "{870696BA-371D-455E-B39A-7B3B14FDE62D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Application", "Application\Application.csproj", "{5C6D5937-49DA-4758-9AE5-C1290975DBB4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{DFE2D8D3-3174-44D9-AC91-C129D208A37B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{7BA1276D-3AF5-4E09-B996-2D91556F8939}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {870696BA-371D-455E-B39A-7B3B14FDE62D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {870696BA-371D-455E-B39A-7B3B14FDE62D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {870696BA-371D-455E-B39A-7B3B14FDE62D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {870696BA-371D-455E-B39A-7B3B14FDE62D}.Release|Any CPU.Build.0 = Release|Any CPU - {5C6D5937-49DA-4758-9AE5-C1290975DBB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5C6D5937-49DA-4758-9AE5-C1290975DBB4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5C6D5937-49DA-4758-9AE5-C1290975DBB4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5C6D5937-49DA-4758-9AE5-C1290975DBB4}.Release|Any CPU.Build.0 = Release|Any CPU - {DFE2D8D3-3174-44D9-AC91-C129D208A37B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DFE2D8D3-3174-44D9-AC91-C129D208A37B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DFE2D8D3-3174-44D9-AC91-C129D208A37B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DFE2D8D3-3174-44D9-AC91-C129D208A37B}.Release|Any CPU.Build.0 = Release|Any CPU - {7BA1276D-3AF5-4E09-B996-2D91556F8939}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7BA1276D-3AF5-4E09-B996-2D91556F8939}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7BA1276D-3AF5-4E09-B996-2D91556F8939}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7BA1276D-3AF5-4E09-B996-2D91556F8939}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/backend/src/Migrations/20251224181902_initial.Designer.cs b/backend/src/Migrations/20251224181902_initial.Designer.cs new file mode 100644 index 0000000..08accd9 --- /dev/null +++ b/backend/src/Migrations/20251224181902_initial.Designer.cs @@ -0,0 +1,50 @@ +// +using JellyGlass.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace JellyGlassBackend.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20251224181902_initial")] + partial class initial + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.11"); + + modelBuilder.Entity("JellyGlass.Models.Server", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Owner") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Servers"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/Migrations/20251224181902_initial.cs b/backend/src/Migrations/20251224181902_initial.cs new file mode 100644 index 0000000..18bdaea --- /dev/null +++ b/backend/src/Migrations/20251224181902_initial.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace JellyGlassBackend.Migrations +{ + /// + public partial class initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Servers", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Owner = table.Column(type: "TEXT", nullable: false), + Url = table.Column(type: "TEXT", nullable: false), + Password = table.Column(type: "TEXT", nullable: false), + Username = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Servers", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Servers"); + } + } +} diff --git a/backend/src/Migrations/DatabaseContextModelSnapshot.cs b/backend/src/Migrations/DatabaseContextModelSnapshot.cs new file mode 100644 index 0000000..335317c --- /dev/null +++ b/backend/src/Migrations/DatabaseContextModelSnapshot.cs @@ -0,0 +1,47 @@ +// +using JellyGlass.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace JellyGlassBackend.Migrations +{ + [DbContext(typeof(DatabaseContext))] + partial class DatabaseContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.11"); + + modelBuilder.Entity("JellyGlass.Models.Server", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Owner") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Servers"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/Models/ItemDTO.cs b/backend/src/Models/ItemDTO.cs new file mode 100644 index 0000000..6cde21f --- /dev/null +++ b/backend/src/Models/ItemDTO.cs @@ -0,0 +1,29 @@ +using JellyGlass.Models.JellyfinApi; + +namespace JellyGlass.Models; + +public class ItemDTO +{ + public ItemDTO() { } + + public ItemDTO(Item item, string ServerUrl) + { + ID = item.Id; + Name = item.Name; + ServerID = item.ServerId; + this.ServerUrl = ServerUrl; + Type = item.Type; + Index = item.IndexNumber; + ParentId = item.ParentId; + ThumbnailUrl = $"{this.ServerUrl}/Items/{ID}/Images/Primary"; + } + + public string ID { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string ServerID { get; set; } = string.Empty; + public string ServerUrl { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + public int? Index { get; set; } + public string? ParentId { get; set; } + public string? ThumbnailUrl { get; set; } +} \ No newline at end of file diff --git a/backend/src/Models/JellyfinApi/AuthResponseModels.cs b/backend/src/Models/JellyfinApi/AuthResponseModels.cs new file mode 100644 index 0000000..02e686a --- /dev/null +++ b/backend/src/Models/JellyfinApi/AuthResponseModels.cs @@ -0,0 +1,14 @@ +namespace JellyGlass.Models.JellyfinApi; + +public class AuthResponse +{ + public required User User { get; set; } + public required string AccessToken { get; set; } + public required string ServerId { get; set; } +} + +public class User +{ + public required string Id { get; set; } +} + diff --git a/backend/src/Models/JellyfinApi/Item.cs b/backend/src/Models/JellyfinApi/Item.cs new file mode 100644 index 0000000..9d0bc38 --- /dev/null +++ b/backend/src/Models/JellyfinApi/Item.cs @@ -0,0 +1,24 @@ +namespace JellyGlass.Models.JellyfinApi; + +public class Item +{ + public string Name { get; set; } = string.Empty; + public string ServerId { get; set; } = string.Empty; + public string Id { get; set; } = string.Empty; + public DateTime DateCreated { get; set; } + public bool CanDownload { get; set; } + public string SortName { get; set; } = string.Empty; + public int? IndexNumber { get; set; } + public bool IsFolder { get; set; } //Whether item has children or not + public string? ParentId { get; set; } + public int? ParentIndexNumber { get; set; } + public string? PremiereDate { get; set; } + public int? ProductionYear { get; set; } + public string? SeriesName { get; set; } + public string? SeriesId { get; set; } + public string? SeasonId { get; set; } + public string? SeasonName { get; set; } + public string Type { get; set; } = string.Empty; + public double PrimaryImageAspectRatio { get; set; } + public string? CollectionType { get; set; } +} \ No newline at end of file diff --git a/backend/src/Models/JellyfinApi/ItemsResponse.cs b/backend/src/Models/JellyfinApi/ItemsResponse.cs new file mode 100644 index 0000000..8f38aef --- /dev/null +++ b/backend/src/Models/JellyfinApi/ItemsResponse.cs @@ -0,0 +1,8 @@ +namespace JellyGlass.Models.JellyfinApi; + +public class ItemResponse +{ + public List Items { get; set; } = []; + public int TotalRecordCount { get; set; } + public int StartIndex { get; set; } +} \ No newline at end of file diff --git a/backend/src/Models/Library.cs b/backend/src/Models/Library.cs new file mode 100644 index 0000000..3f9c2a1 --- /dev/null +++ b/backend/src/Models/Library.cs @@ -0,0 +1,8 @@ + +namespace JellyGlass.Models; + +public class Library +{ + public string Name { get; set; } = string.Empty; + public string ThumbnailUrl { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/backend/src/Models/Server.cs b/backend/src/Models/Server.cs new file mode 100644 index 0000000..0b31f5f --- /dev/null +++ b/backend/src/Models/Server.cs @@ -0,0 +1,10 @@ +namespace JellyGlass.Models; + +public class Server +{ + public string Owner { get; set; } = string.Empty; + public string Url { get; set; } = string.Empty; + public string Id { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + public string Username { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/backend/src/Program.cs b/backend/src/Program.cs new file mode 100644 index 0000000..79e7ec8 --- /dev/null +++ b/backend/src/Program.cs @@ -0,0 +1,41 @@ +using JellyGlass.Repositories; +using JellyGlass.Services; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); +builder.Services.AddControllers(); + +builder.Configuration.GetSection("TestingLogin"); + +string dbConnectionString; + +if (builder.Environment.IsDevelopment()) +{ + dbConnectionString = "Data Source=JellyGlass-test.db;"; +} +else +{ + dbConnectionString = "Data Source./JellyGlass.db;"; +} + +builder.Services.AddSqlite(dbConnectionString); + +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddScoped(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); +app.MapControllers(); + +app.Run(); diff --git a/backend/src/WebApi/Properties/launchSettings.json b/backend/src/Properties/launchSettings.json similarity index 80% rename from backend/src/WebApi/Properties/launchSettings.json rename to backend/src/Properties/launchSettings.json index 89549ba..6206ac3 100644 --- a/backend/src/WebApi/Properties/launchSettings.json +++ b/backend/src/Properties/launchSettings.json @@ -5,7 +5,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, - "applicationUrl": "http://localhost:5152", + "applicationUrl": "http://localhost:5092", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } @@ -14,7 +14,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, - "applicationUrl": "https://localhost:7106;http://localhost:5152", + "applicationUrl": "https://localhost:7226;http://localhost:5092", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/backend/src/Repositories/DatabaseContext.cs b/backend/src/Repositories/DatabaseContext.cs new file mode 100644 index 0000000..c6e3ae1 --- /dev/null +++ b/backend/src/Repositories/DatabaseContext.cs @@ -0,0 +1,15 @@ +using JellyGlass.Models; +using Microsoft.EntityFrameworkCore; + +namespace JellyGlass.Repositories; + +public class DatabaseContext : DbContext +{ + public DatabaseContext(DbContextOptions options) + : base(options) + { + + } + + public DbSet Servers { get; set; } +} \ No newline at end of file diff --git a/backend/src/Core/Interfaces/IServerRepository.cs b/backend/src/Repositories/IServerRepository.cs similarity index 52% rename from backend/src/Core/Interfaces/IServerRepository.cs rename to backend/src/Repositories/IServerRepository.cs index 3f4fbd8..489985f 100644 --- a/backend/src/Core/Interfaces/IServerRepository.cs +++ b/backend/src/Repositories/IServerRepository.cs @@ -1,6 +1,6 @@ -using JellyGlass.Core.Entities; +using JellyGlass.Models; -namespace JellyGlass.Core.Interfaces; +namespace JellyGlass.Repositories; public interface IServerRepository { diff --git a/backend/src/Repositories/JellyfinApiClient.cs b/backend/src/Repositories/JellyfinApiClient.cs new file mode 100644 index 0000000..42928f7 --- /dev/null +++ b/backend/src/Repositories/JellyfinApiClient.cs @@ -0,0 +1,149 @@ +using System.Net; +using System.Net.Http.Headers; +using System.Text; +using System.Text.Json; +using JellyGlass.Exceptions; +using JellyGlass.Models; +using JellyGlass.Models.JellyfinApi; + +namespace JellyGlass.Repositories; + +public class JellyfinApiClient +{ + private string _apiKey = string.Empty; + public readonly string InstanceUrl; + private readonly HttpClient _client; + private readonly string _username, _password; + + public JellyfinApiClient(string instanceUrl, string username, string password) + { + InstanceUrl = instanceUrl; + _client = new HttpClient(); + _client.DefaultRequestHeaders.Clear(); + _username = username; + _password = password; + } + + public async Task GetInstanceLibraries() + { + try + { + var request = new HttpRequestMessage(HttpMethod.Get, $"{InstanceUrl}/Library/MediaFolders"); + var response = await MakeRequest(request); + + response.EnsureSuccessStatusCode(); + + var apiResponse = await response.Content.ReadFromJsonAsync(); + + return apiResponse!; + } + catch (HttpRequestException e) + { + throw new JellyfinApiClientException(e.Message); + } + } + + public async Task GetItemChildren(string itemId) + { + try + { + var request = new HttpRequestMessage(HttpMethod.Get, $"{InstanceUrl}/items?ParentId={itemId}"); + + var response = await MakeRequest(request); + + response.EnsureSuccessStatusCode(); + + var apiResponse = await response.Content.ReadFromJsonAsync(); + + return apiResponse!; + } + catch (HttpRequestException e) + { + throw new JellyfinApiClientException(e.Message); + } + } + + public async Task GetItems(string searchTerm = "", string years = "", string itemTypes = "", string limit = "", string parentId = "") + { + var query = new Dictionary(); + + if (searchTerm != String.Empty) + { + query.Add("SearchTerm", searchTerm); + } + + throw new NotImplementedException(); + } + + public async Task Authenticate() + { + var request = new HttpRequestMessage(HttpMethod.Post, $"{InstanceUrl}/Users/AuthenticateByName"); + + request.Headers.Authorization = new AuthenticationHeaderValue("MediaBrowser", GetAuthHeader()); + + var body = new + { + Username = _username, + Pw = _password + }; + + request.Content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json"); + + try + { + var response = await _client.SendAsync(request); + + response.EnsureSuccessStatusCode(); + + var authResponse = await response.Content.ReadFromJsonAsync(); + + _apiKey = authResponse!.AccessToken; + } + catch (HttpRequestException e) + { + //TODO: What to do on an exception + throw new JellyfinApiClientException(e.Message); + } + } + + private async Task MakeRequest(HttpRequestMessage request) + { + request.Headers.Authorization = new AuthenticationHeaderValue("MediaBrowser", GetAuthHeader()); + + HttpResponseMessage response; + + try + { + response = await _client.SendAsync(request); + } + catch (HttpRequestException e) + { + if (e.StatusCode == HttpStatusCode.Unauthorized) + { + await Authenticate(); + + request.Headers.Authorization = new AuthenticationHeaderValue("MediaBrowser", GetAuthHeader()); + + response = await _client.SendAsync(request); + } + else + { + throw new JellyfinApiClientException(e.Message); + } + } + + return response; + } + + private string GetAuthHeader() + { + var header = "Client=Test, Device=Test, DeviceId=Test, Version=1"; + + if (_apiKey != String.Empty) + { + header += ", Token=" + _apiKey; + } + + return header; + } +} \ No newline at end of file diff --git a/backend/src/Repositories/ServerRepository.cs b/backend/src/Repositories/ServerRepository.cs new file mode 100644 index 0000000..4fdb60d --- /dev/null +++ b/backend/src/Repositories/ServerRepository.cs @@ -0,0 +1,21 @@ +using JellyGlass.Models; +using Microsoft.EntityFrameworkCore; + +namespace JellyGlass.Repositories; + +public class ServerRepository : IServerRepository +{ + private DatabaseContext _context; + + public ServerRepository(DatabaseContext context) + { + _context = context; + } + + public async Task GetServers() + { + var servers = await _context.Servers.ToArrayAsync(); + + return servers; + } +} \ No newline at end of file diff --git a/backend/src/Services/ILibraryService.cs b/backend/src/Services/ILibraryService.cs new file mode 100644 index 0000000..72a9e6f --- /dev/null +++ b/backend/src/Services/ILibraryService.cs @@ -0,0 +1,14 @@ +using JellyGlass.Models; + +namespace JellyGlass.Services; + +public interface ILibraryService +{ + public Task GetLibraries(); + public Task GetItemsFromLibrary(string libraryName); + + + // public Task GetChildrenFromItems(ItemDTO[] items); + // public Task GetItemsByName(string name, string itemType); + // public Task GetItemsByType(string itemType); +} \ No newline at end of file diff --git a/backend/src/Services/IServerService.cs b/backend/src/Services/IServerService.cs new file mode 100644 index 0000000..82c633b --- /dev/null +++ b/backend/src/Services/IServerService.cs @@ -0,0 +1,10 @@ +using JellyGlass.Repositories; + +namespace JellyGlass.Services; + +public interface IServerService +{ + public Task GetJellyfinClients(); + // public JellyfinApiClient GetClientForServer(string url); + // public JellyfinApiClient GetClientForServerId(string serverId); +} \ No newline at end of file diff --git a/backend/src/Services/LibraryService.cs b/backend/src/Services/LibraryService.cs new file mode 100644 index 0000000..efdabd1 --- /dev/null +++ b/backend/src/Services/LibraryService.cs @@ -0,0 +1,74 @@ +using JellyGlass.Models; + +namespace JellyGlass.Services; + +public class LibraryService : ILibraryService +{ + private IServerService _serverService; + + public LibraryService(IServerService serverService) + { + _serverService = serverService; + } + + public async Task GetLibraries() + { + var clients = await _serverService.GetJellyfinClients(); + + var libraries = new Dictionary(); + + foreach (var client in clients) + { + var clientLibraries = await client.GetInstanceLibraries(); + + foreach (var library in clientLibraries.Items) + { + if (!libraries.ContainsKey(library.Name)) + { + + libraries.Add(library.Name, new Library() + { + Name = library.Name, + ThumbnailUrl = $"{client.InstanceUrl}/Items/{library.Id}/Primary" + }); + } + } + } + + return libraries.Values.ToArray(); + } + + public async Task GetItemsFromLibrary(string libraryName) + { + throw new NotImplementedException(); + } + + // public async Task GetChildrenFromItems(ItemDTO[] items) + // { + // var children = new List(); + + // foreach (var item in items) + // { + // var client = _serverService.GetClientForServerId(item.ServerID); + + // var itemChildren = await client.GetItemChildren(item.ID); + + // foreach (var child in itemChildren.Items) + // { + // children.Add(new ItemDTO(child, client.InstanceUrl)); + // } + // } + + // return children.ToArray(); + // } + + // public async Task GetItemsByName(string name, string itemType) + // { + + // } + + // public async Task GetItemsByType(string itemType) + // { + + // } +} \ No newline at end of file diff --git a/backend/src/Services/ServerService.cs b/backend/src/Services/ServerService.cs new file mode 100644 index 0000000..935d1b8 --- /dev/null +++ b/backend/src/Services/ServerService.cs @@ -0,0 +1,52 @@ +using JellyGlass.Exceptions; +using JellyGlass.Models; +using JellyGlass.Repositories; + +namespace JellyGlass.Services; + +public class ServerService : IServerService +{ + private IServerRepository _repository; + private static JellyfinApiClient[] _clients = []; + private ILogger _logger; + + public ServerService(IServerRepository repository, ILogger logger) + { + _repository = repository; + _logger = logger; + } + + public async Task GetJellyfinClients() + { + if (!_clients.Any()) + { + await LoadClients(); + } + + return _clients; + } + + private async Task LoadClients() + { + var servers = await _repository.GetServers(); + var clients = new List(); + + foreach (var server in servers) + { + var client = new JellyfinApiClient(server.Url, server.Username, server.Password); + + try + { + await client.Authenticate(); + } + catch (JellyfinApiClientException e) + { + + } + + clients.Add(client); + } + + _clients = clients.ToArray(); + } +} \ No newline at end of file diff --git a/backend/src/WebApi/Controllers/ItemController.cs b/backend/src/WebApi/Controllers/ItemController.cs deleted file mode 100644 index 289e173..0000000 --- a/backend/src/WebApi/Controllers/ItemController.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using JellyGlass.Core.Interfaces; - -namespace JellyGlass.WebApi.Controllers; - -[ApiController] -[Route("[controller]")] -public class ItemController : ControllerBase -{ - private ILogger _logger; - private IItemService _service; - - public ItemController(ILogger logger, IItemService service) - { - _service = service; - _logger = logger; - } - - public async Task GetItemsForLibrary(string libraryId) - { - var items = await _service.GetItemsFromLibrary(libraryId); - - return Ok(items); - } -} \ No newline at end of file diff --git a/backend/src/WebApi/Controllers/LibraryController.cs b/backend/src/WebApi/Controllers/LibraryController.cs deleted file mode 100644 index b10fb75..0000000 --- a/backend/src/WebApi/Controllers/LibraryController.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using JellyGlass.Core.Interfaces; - -namespace JellyGlass.WebApi.Controllers; - -[ApiController] -[Route("[controller]")] -public class LibraryController : ControllerBase -{ - private ILogger _logger; - private ILibraryService _service; - - public LibraryController(ILogger logger, ILibraryService service) - { - _logger = logger; - _service = service; - } - - [HttpGet] - public async Task GetLibraries() - { - var libraries = await _service.GetLibraries(); - - return Ok(libraries); - } -} \ No newline at end of file diff --git a/backend/src/WebApi/Controllers/ServerController.cs b/backend/src/WebApi/Controllers/ServerController.cs deleted file mode 100644 index 9aa7147..0000000 --- a/backend/src/WebApi/Controllers/ServerController.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using JellyGlass.Core.Interfaces; - -namespace JellyGlass.WebApi.Controllers; - -[ApiController] -[Route("[controller]")] -public class ServerController : ControllerBase -{ - private ILogger _logger; - private IServerService _service; - - public ServerController(ILogger logger, IServerService service) - { - _logger = logger; - _service = service; - } - - public async Task GetServers() - { - var servers = await _service.GetServers(); - - return Ok(servers); - } -} \ No newline at end of file diff --git a/backend/src/WebApi/Program.cs b/backend/src/WebApi/Program.cs deleted file mode 100644 index 1829f66..0000000 --- a/backend/src/WebApi/Program.cs +++ /dev/null @@ -1,19 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); - -// Add services to the container. -// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi -builder.Services.AddOpenApi(); -builder.Services.AddControllers(); - -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.MapOpenApi(); -} - -app.UseHttpsRedirection(); -app.MapControllers(); - -app.Run(); diff --git a/backend/src/WebApi/WebApi.csproj b/backend/src/WebApi/WebApi.csproj deleted file mode 100644 index b5cfb60..0000000 --- a/backend/src/WebApi/WebApi.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net9.0 - enable - enable - - - - - - - - - - - - - diff --git a/backend/src/WebApi/WebApi.http b/backend/src/WebApi/WebApi.http deleted file mode 100644 index f3e4d2c..0000000 --- a/backend/src/WebApi/WebApi.http +++ /dev/null @@ -1,6 +0,0 @@ -@WebApi_HostAddress = http://localhost:5152 - -GET {{WebApi_HostAddress}}/weatherforecast/ -Accept: application/json - -### diff --git a/backend/src/WebApi/appsettings.Development.json b/backend/src/WebApi/appsettings.Development.json deleted file mode 100644 index 0c208ae..0000000 --- a/backend/src/WebApi/appsettings.Development.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} diff --git a/backend/src/appsettings.Development.json b/backend/src/appsettings.Development.json new file mode 100644 index 0000000..75e7744 --- /dev/null +++ b/backend/src/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} \ No newline at end of file diff --git a/backend/src/WebApi/appsettings.json b/backend/src/appsettings.json similarity index 100% rename from backend/src/WebApi/appsettings.json rename to backend/src/appsettings.json diff --git a/backend/src/src.http b/backend/src/src.http new file mode 100644 index 0000000..fffe865 --- /dev/null +++ b/backend/src/src.http @@ -0,0 +1,6 @@ +@src_HostAddress = http://localhost:5092 + +GET {{src_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/pythonBackend/venv/bin/Activate.ps1 b/pythonBackend/venv/bin/Activate.ps1 new file mode 100644 index 0000000..b49d77b --- /dev/null +++ b/pythonBackend/venv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/pythonBackend/venv/bin/activate b/pythonBackend/venv/bin/activate new file mode 100644 index 0000000..d7469ec --- /dev/null +++ b/pythonBackend/venv/bin/activate @@ -0,0 +1,70 @@ +# This file must be used with "source bin/activate" *from bash* +# You cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # Call hash to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + hash -r 2> /dev/null + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +# on Windows, a path can contain colons and backslashes and has to be converted: +if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then + # transform D:\path\to\venv to /d/path/to/venv on MSYS + # and to /cygdrive/d/path/to/venv on Cygwin + export VIRTUAL_ENV=$(cygpath /home/fox/Documents/programming/Projects/JellyGlass/pythonBackend/venv) +else + # use the path as-is + export VIRTUAL_ENV=/home/fox/Documents/programming/Projects/JellyGlass/pythonBackend/venv +fi + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/"bin":$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1='(venv) '"${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT='(venv) ' + export VIRTUAL_ENV_PROMPT +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/pythonBackend/venv/bin/activate.csh b/pythonBackend/venv/bin/activate.csh new file mode 100644 index 0000000..1ea5a84 --- /dev/null +++ b/pythonBackend/venv/bin/activate.csh @@ -0,0 +1,27 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. + +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV /home/fox/Documents/programming/Projects/JellyGlass/pythonBackend/venv + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/"bin":$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = '(venv) '"$prompt" + setenv VIRTUAL_ENV_PROMPT '(venv) ' +endif + +alias pydoc python -m pydoc + +rehash diff --git a/pythonBackend/venv/bin/activate.fish b/pythonBackend/venv/bin/activate.fish new file mode 100644 index 0000000..499a16e --- /dev/null +++ b/pythonBackend/venv/bin/activate.fish @@ -0,0 +1,69 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/). You cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV /home/fox/Documents/programming/Projects/JellyGlass/pythonBackend/venv + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/"bin $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) '(venv) ' (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT '(venv) ' +end