Compare commits
1 Commits
10.10
...
rebuild-db
Author | SHA1 | Date | |
---|---|---|---|
|
35cbf57f41 |
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@ -55,13 +55,13 @@ jobs:
|
||||
run: dotnet restore
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
|
||||
uses: github/codeql-action/init@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-extended
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
|
||||
uses: github/codeql-action/autobuild@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
|
||||
uses: github/codeql-action/analyze@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4
|
||||
|
@ -8,7 +8,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
@ -455,10 +455,8 @@
|
||||
<h3 style="margin: 0">Analyzer actions</h3>
|
||||
<p style="margin: 0">
|
||||
Choose how segments should be analyzed for this season.<br />
|
||||
<i>
|
||||
Default uses all available detection methods (Chromaprint, Chapter, and BlackFrame for credits).<br />
|
||||
Select specific methods to limit analysis, or None to skip detection entirely.
|
||||
</i>
|
||||
Default uses all available detection methods (Chromaprint, Chapter, and BlackFrame for credits).<br />
|
||||
Select specific methods to limit analysis, or None to skip detection entirely.
|
||||
</p>
|
||||
<br />
|
||||
|
||||
@ -625,9 +623,10 @@
|
||||
</div>
|
||||
|
||||
<div id="timestampErrorDiv" style="display: none">
|
||||
<p>
|
||||
<textarea id="timestampError" rows="2" cols="75" readonly></textarea>
|
||||
</p>
|
||||
<br />
|
||||
<textarea id="timestampError" rows="2" cols="75" readonly></textarea>
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div id="fingerprintVisualizer" style="display: none">
|
||||
@ -666,11 +665,12 @@
|
||||
|
||||
<span>Shift amount:</span>
|
||||
<input type="number" min="-3000" max="3000" value="0" id="offset" />
|
||||
<p>
|
||||
<br />
|
||||
<span id="suggestedShifts">
|
||||
<span>Suggested shifts: </span>
|
||||
</span>
|
||||
</p>
|
||||
<br />
|
||||
<br />
|
||||
<canvas id="troubleshooter" style="display: none"></canvas>
|
||||
<span id="timestampContainer">
|
||||
<span id="timestamps"></span>
|
||||
@ -679,27 +679,26 @@
|
||||
</span>
|
||||
<br />
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div id="eraseSeasonContainer" style="display: none">
|
||||
<p>
|
||||
<button is="emby-button" id="btnEraseSeasonTimestamps" class="button-submit emby-button" type="button">Erase all timestamps for this season</button>
|
||||
<button is="emby-button" id="btnEraseSeasonTimestamps" class="button-submit emby-button" type="button">Erase all timestamps for this season</button>
|
||||
|
||||
<input type="checkbox" id="eraseSeasonCacheCheckbox" style="margin-left: 10px" />
|
||||
<label for="eraseSeasonCacheCheckbox" style="margin-left: 5px">Erase cached fingerprint files</label>
|
||||
</p>
|
||||
<input type="checkbox" id="eraseSeasonCacheCheckbox" style="margin-left: 10px" />
|
||||
<label for="eraseSeasonCacheCheckbox" style="margin-left: 5px">Erase cached fingerprint files</label>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div id="eraseMovieContainer" style="display: none">
|
||||
<p>
|
||||
<button is="emby-button" id="btnEraseMovieTimestamps" class="button-submit emby-button" type="button">Erase all timestamps for this movie</button>
|
||||
<button is="emby-button" id="btnEraseMovieTimestamps" class="button-submit emby-button" type="button">Erase all timestamps for this movie</button>
|
||||
|
||||
<input type="checkbox" id="eraseMovieCacheCheckbox" style="margin-left: 10px" />
|
||||
<label for="eraseMovieCacheCheckbox" style="margin-left: 5px">Erase cached fingerprint files</label>
|
||||
</p>
|
||||
<input type="checkbox" id="eraseMovieCacheCheckbox" style="margin-left: 10px" />
|
||||
<label for="eraseMovieCacheCheckbox" style="margin-left: 5px">Erase cached fingerprint files</label>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<p>
|
||||
<div>
|
||||
<button is="emby-button" class="button-submit emby-button" id="btnEraseIntroTimestamps">Erase all introduction timestamps (globally)</button>
|
||||
<br />
|
||||
|
||||
@ -710,16 +709,21 @@
|
||||
<br />
|
||||
|
||||
<button is="emby-button" class="button-submit emby-button" id="btnErasePreviewTimestamps">Erase all preview timestamps (globally)</button>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="eraseModeCacheCheckbox" style="margin-left: 10px" />
|
||||
<label for="eraseModeCacheCheckbox" style="margin-left: 5px">Erase global cached fingerprint files</label>
|
||||
</div>
|
||||
<div>
|
||||
<button is="emby-button" class="button-submit emby-button" id="btnRebuildDatabase">Rebuild database</button>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
</details>
|
||||
|
||||
<details id="support">
|
||||
<summary>Intro Skipper Support Log</summary>
|
||||
<summary>Support Bundle Info</summary>
|
||||
|
||||
<textarea id="supportBundle" rows="20" cols="75" readonly></textarea>
|
||||
</details>
|
||||
@ -757,6 +761,7 @@
|
||||
var btnEraseRecapTimestamps = document.querySelector("button#btnEraseRecapTimestamps");
|
||||
var btnEraseCreditTimestamps = document.querySelector("button#btnEraseCreditTimestamps");
|
||||
var btnErasePreviewTimestamps = document.querySelector("button#btnErasePreviewTimestamps");
|
||||
var btnRebuildDatabase = document.querySelector("button#btnRebuildDatabase");
|
||||
|
||||
// all plugin configuration fields that can be get or set with .value (i.e. strings or numbers).
|
||||
var configurationFields = [
|
||||
@ -1503,6 +1508,9 @@
|
||||
eraseTimestamps("Preview");
|
||||
e.preventDefault();
|
||||
});
|
||||
btnRebuildDatabase.addEventListener("click", () => {
|
||||
fetchWithAuth("Intros/RebuildDatabase", "POST", null);
|
||||
});
|
||||
btnSeasonEraseTimestamps.addEventListener("click", () => {
|
||||
Dashboard.confirm("Are you sure you want to erase all timestamps for this season?", "Confirm timestamp erasure", (result) => {
|
||||
if (!result) {
|
||||
|
@ -251,6 +251,20 @@ public class SkipIntroController(MediaSegmentUpdateManager mediaSegmentUpdateMan
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds the database.
|
||||
/// </summary>
|
||||
/// <response code="204">Database rebuilt.</response>
|
||||
/// <returns>No content.</returns>
|
||||
[Authorize(Policy = Policies.RequiresElevation)]
|
||||
[HttpPost("Intros/RebuildDatabase")]
|
||||
public ActionResult RebuildDatabase()
|
||||
{
|
||||
using var db = new IntroSkipperDbContext(Plugin.Instance!.DbPath);
|
||||
db.RebuildDatabase();
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user interface configuration.
|
||||
/// </summary>
|
||||
|
@ -109,39 +109,73 @@ public class IntroSkipperDbContext : DbContext
|
||||
/// </summary>
|
||||
public void ApplyMigrations()
|
||||
{
|
||||
// If migrations table exists, just apply pending migrations normally
|
||||
if (Database.GetAppliedMigrations().Any() || !Database.CanConnect())
|
||||
// If database doesn't exist or can't connect, create it with migrations
|
||||
if (!Database.CanConnect())
|
||||
{
|
||||
Database.Migrate();
|
||||
return;
|
||||
}
|
||||
|
||||
// If migrations table exists, apply pending migrations normally
|
||||
if (Database.GetAppliedMigrations().Any())
|
||||
{
|
||||
Database.Migrate();
|
||||
return;
|
||||
}
|
||||
|
||||
// For databases without migration history
|
||||
try
|
||||
RebuildDatabase();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds the database while preserving valid segments and season information.
|
||||
/// </summary>
|
||||
public void RebuildDatabase()
|
||||
{
|
||||
// Backup existing data
|
||||
List<DbSegment> segments = [];
|
||||
List<DbSeasonInfo> seasonInfos = [];
|
||||
using (var db = new IntroSkipperDbContext(_dbPath))
|
||||
{
|
||||
// Backup existing data
|
||||
List<DbSegment> segments;
|
||||
using (var db = new IntroSkipperDbContext(_dbPath))
|
||||
try
|
||||
{
|
||||
segments = [.. db.DbSegment.AsEnumerable().Where(s => s.ToSegment().Valid)];
|
||||
}
|
||||
|
||||
// Delete old database
|
||||
Database.EnsureDeleted();
|
||||
|
||||
// Create new database with proper migration history
|
||||
Database.Migrate();
|
||||
|
||||
// Restore the data
|
||||
using (var db = new IntroSkipperDbContext(_dbPath))
|
||||
catch (Exception ex)
|
||||
{
|
||||
db.DbSegment.AddRange(segments);
|
||||
db.SaveChanges();
|
||||
throw new InvalidOperationException("Failed to read DbSegment data", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
seasonInfos = [.. db.DbSeasonInfo];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to read DbSeasonInfo data", ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
// Delete old database
|
||||
Database.EnsureDeleted();
|
||||
|
||||
// Create new database with proper migration history
|
||||
Database.Migrate();
|
||||
|
||||
// Restore the data
|
||||
using (var db = new IntroSkipperDbContext(_dbPath))
|
||||
{
|
||||
throw new InvalidOperationException("Failed to apply migrations", ex);
|
||||
if (segments.Count > 0)
|
||||
{
|
||||
db.DbSegment.AddRange(segments);
|
||||
}
|
||||
|
||||
if (seasonInfos.Count > 0)
|
||||
{
|
||||
db.DbSeasonInfo.AddRange(seasonInfos);
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>IntroSkipper</RootNamespace>
|
||||
<AssemblyVersion>1.10.10.11</AssemblyVersion>
|
||||
<FileVersion>1.10.10.11</FileVersion>
|
||||
<AssemblyVersion>1.10.10.10</AssemblyVersion>
|
||||
<FileVersion>1.10.10.10</FileVersion>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
|
@ -77,6 +77,15 @@ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
|
||||
Directory.CreateDirectory(FingerprintCachePath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
LegacyMigrations.MigrateAll(this, serverConfiguration, logger, applicationPaths);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError("Failed to perform migrations. Error: {Error}", ex);
|
||||
}
|
||||
|
||||
// Initialize database, restore timestamps if available.
|
||||
try
|
||||
{
|
||||
@ -88,15 +97,6 @@ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
|
||||
logger.LogWarning("Error initializing database: {Exception}", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
LegacyMigrations.MigrateAll(this, serverConfiguration, logger, applicationPaths);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError("Failed to perform migrations. Error: {Error}", ex);
|
||||
}
|
||||
|
||||
FFmpegWrapper.CheckFFmpegVersion();
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ https://manifest.intro-skipper.org/manifest.json
|
||||
- #### [Scheduled tasks fail instantly](https://github.com/intro-skipper/intro-skipper/wiki/Troubleshooting#scheduled-tasks-fail-instantly)
|
||||
- #### [Plugin settings not saved](https://github.com/intro-skipper/intro-skipper/wiki/Troubleshooting#plugin-settings-not-saved)
|
||||
- #### [Skip button is not visible](https://github.com/intro-skipper/intro-skipper/wiki/Troubleshooting#skip-button-is-not-visible)
|
||||
- #### [Auto skip is not working](https://github.com/intro-skipper/intro-skipper/wiki/Troubleshooting#auto-skip-is-not-working)
|
||||
- #### [Autoskip is not working](https://github.com/intro-skipper/intro-skipper/wiki/Troubleshooting#autoskip-is-not-working)
|
||||
|
||||
## [API Documentation](https://github.com/intro-skipper/intro-skipper/blob/master/docs/api.md)
|
||||
|
||||
|
@ -9,13 +9,21 @@
|
||||
"imageUrl": "https://raw.githubusercontent.com/intro-skipper/intro-skipper/master/images/logo.png",
|
||||
"versions": [
|
||||
{
|
||||
"version": "1.10.10.11",
|
||||
"changelog": "- See the full changelog at [GitHub](https://github.com/intro-skipper/intro-skipper/releases/tag/10.10/v1.10.10.11)\n",
|
||||
"version": "1.10.10.10",
|
||||
"changelog": "- See the full changelog at [GitHub](https://github.com/intro-skipper/intro-skipper/releases/tag/10.10/v1.10.10.10)\n",
|
||||
"targetAbi": "10.10.3.0",
|
||||
"sourceUrl": "https://github.com/intro-skipper/intro-skipper/releases/download/10.10/v1.10.10.11/intro-skipper-v1.10.10.11.zip",
|
||||
"checksum": "30a71fd3996e0fbe9076371539b1ca56",
|
||||
"timestamp": "2024-11-25T17:07:33Z"
|
||||
"sourceUrl": "https://github.com/intro-skipper/intro-skipper/releases/download/10.10/v1.10.10.10/intro-skipper-v1.10.10.10.zip",
|
||||
"checksum": "96ec29871e726ece01fbf7ccb24ae392",
|
||||
"timestamp": "2024-11-24T18:33:26Z"
|
||||
},
|
||||
{
|
||||
"version": "1.10.10.9",
|
||||
"changelog": "- See the full changelog at [GitHub](https://github.com/intro-skipper/intro-skipper/releases/tag/10.10/v1.10.10.9)\n",
|
||||
"targetAbi": "10.10.2.0",
|
||||
"sourceUrl": "https://github.com/intro-skipper/intro-skipper/releases/download/10.10/v1.10.10.9/intro-skipper-v1.10.10.9.zip",
|
||||
"checksum": "a39436ee4476a4e74acbafbaf1008dfb",
|
||||
"timestamp": "2024-11-17T21:14:18Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user