mirror of
https://github.com/chrisbenincasa/tunarr.git
synced 2026-04-18 09:03:35 -04:00
fix: fix channel deletes when channel is associated with fillers (#889)
This commit is contained in:
committed by
GitHub
parent
03f57e0ed5
commit
83126c8659
1
.prettierignore
Normal file
1
.prettierignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
server/src/migrations/**/*.ts
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.mts", "*.tsx"],
|
"files": ["*.ts", "*.mts", "*.tsx"],
|
||||||
|
"excludeFiles": ["server/src/migrations/**/*.ts"],
|
||||||
"options": {
|
"options": {
|
||||||
"parser": "typescript"
|
"parser": "typescript"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { Migration20240618005544 } from './src/migrations/Migration2024061800554
|
|||||||
import { Migration20240719145409 } from './src/migrations/Migration20240719145409.js';
|
import { Migration20240719145409 } from './src/migrations/Migration20240719145409.js';
|
||||||
import { Migration20240805185042 } from './src/migrations/Migration20240805185042.js';
|
import { Migration20240805185042 } from './src/migrations/Migration20240805185042.js';
|
||||||
import { Migration20240917191535 } from './src/migrations/Migration20240917191535.js';
|
import { Migration20240917191535 } from './src/migrations/Migration20240917191535.js';
|
||||||
|
import { Migration20241014205231 } from './src/migrations/Migration20241014205231.js';
|
||||||
import { DATABASE_LOCATION_ENV_VAR } from './src/util/constants.js';
|
import { DATABASE_LOCATION_ENV_VAR } from './src/util/constants.js';
|
||||||
import { getDefaultDatabaseDirectory } from './src/util/defaults.js';
|
import { getDefaultDatabaseDirectory } from './src/util/defaults.js';
|
||||||
|
|
||||||
@@ -143,6 +144,10 @@ export default defineConfig({
|
|||||||
name: 'add_channel_stream_mode',
|
name: 'add_channel_stream_mode',
|
||||||
class: Migration20240917191535,
|
class: Migration20240917191535,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'cascade_channel_filler_show_deletes',
|
||||||
|
class: Migration20241014205231,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
extensions: [Migrator],
|
extensions: [Migrator],
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"make-exec:macos-arm64": "tsx scripts/makeScriptPackage.ts --target macos-arm64",
|
"make-exec:macos-arm64": "tsx scripts/makeScriptPackage.ts --target macos-arm64",
|
||||||
"make-exec:windows": "tsx scripts/makeScriptPackage.ts --target windows-x64",
|
"make-exec:windows": "tsx scripts/makeScriptPackage.ts --target windows-x64",
|
||||||
"generate-db-migration": "dotenv -e .env.development -- tsx --tsconfig ./tsconfig.build.json src/index.ts db generate-migration",
|
"generate-db-migration": "dotenv -e .env.development -- tsx --tsconfig ./tsconfig.build.json src/index.ts db generate-migration",
|
||||||
|
"generate-db-migration2": "dotenv -e .env.development -- tsx --tsconfig ./tsconfig.build.json scripts/generateDbMigration.ts",
|
||||||
"generate-db-cache": "dotenv -e .env.development -- tsx scripts/generateDbCache.ts",
|
"generate-db-cache": "dotenv -e .env.development -- tsx scripts/generateDbCache.ts",
|
||||||
"generate-db-types": "dotenv -e .env.development -- tsx scripts/genDbTypes.ts",
|
"generate-db-types": "dotenv -e .env.development -- tsx scripts/genDbTypes.ts",
|
||||||
"mikro-orm": "mikro-orm-esm",
|
"mikro-orm": "mikro-orm-esm",
|
||||||
|
|||||||
27
server/scripts/generateDbMigration.ts
Normal file
27
server/scripts/generateDbMigration.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import tmp from 'tmp';
|
||||||
|
import dbConfig from '../mikro-orm.config.js';
|
||||||
|
import { initOrm } from '../src/dao/dataSource';
|
||||||
|
|
||||||
|
const tmpdir = tmp.dirSync({
|
||||||
|
unsafeCleanup: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const dbName = path.join(tmpdir.name, 'db.db');
|
||||||
|
|
||||||
|
console.log(`using temporary database at ${dbName}`);
|
||||||
|
|
||||||
|
const orm = await initOrm({
|
||||||
|
...dbConfig,
|
||||||
|
dbName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const migrationResult = await orm.migrator.createMigration('./src/migrations');
|
||||||
|
|
||||||
|
console.log(`Succcesfully created migration ${migrationResult.fileName}`);
|
||||||
|
|
||||||
|
console.debug(migrationResult.diff);
|
||||||
|
|
||||||
|
await orm.close();
|
||||||
|
|
||||||
|
tmpdir.removeCallback();
|
||||||
@@ -478,6 +478,7 @@ export class ChannelDB {
|
|||||||
try {
|
try {
|
||||||
await this.markLineupFileForDeletion(channelId);
|
await this.markLineupFileForDeletion(channelId);
|
||||||
marked = true;
|
marked = true;
|
||||||
|
|
||||||
const ref = em.getReference(Channel, channelId);
|
const ref = em.getReference(Channel, channelId);
|
||||||
await em.remove(ref).flush();
|
await em.remove(ref).flush();
|
||||||
// Best effort remove references to this channel
|
// Best effort remove references to this channel
|
||||||
@@ -505,6 +506,8 @@ export class ChannelDB {
|
|||||||
channelId,
|
channelId,
|
||||||
e,
|
e,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
Cascade,
|
|
||||||
Collection,
|
Collection,
|
||||||
Entity,
|
Entity,
|
||||||
Enum,
|
Enum,
|
||||||
@@ -191,7 +190,7 @@ export class Channel extends BaseEntity {
|
|||||||
entity: () => FillerShow,
|
entity: () => FillerShow,
|
||||||
pivotEntity: () => ChannelFillerShow,
|
pivotEntity: () => ChannelFillerShow,
|
||||||
mappedBy: (filler) => filler.channels,
|
mappedBy: (filler) => filler.channels,
|
||||||
cascade: [Cascade.PERSIST, Cascade.REMOVE],
|
deleteRule: 'cascade',
|
||||||
})
|
})
|
||||||
fillers = new Collection<FillerShow>(this);
|
fillers = new Collection<FillerShow>(this);
|
||||||
|
|
||||||
@@ -204,7 +203,10 @@ export class Channel extends BaseEntity {
|
|||||||
@Property({ nullable: true })
|
@Property({ nullable: true })
|
||||||
fillerRepeatCooldown?: number; // Seconds
|
fillerRepeatCooldown?: number; // Seconds
|
||||||
|
|
||||||
@ManyToMany(() => CustomShow)
|
@ManyToMany({
|
||||||
|
entity: () => CustomShow,
|
||||||
|
deleteRule: 'cascade',
|
||||||
|
})
|
||||||
customShows = new Collection<CustomShow>(this);
|
customShows = new Collection<CustomShow>(this);
|
||||||
|
|
||||||
// Watermark
|
// Watermark
|
||||||
@@ -219,7 +221,10 @@ export class Channel extends BaseEntity {
|
|||||||
})
|
})
|
||||||
transcoding?: IType<ChannelTranscodingSettings, string>;
|
transcoding?: IType<ChannelTranscodingSettings, string>;
|
||||||
|
|
||||||
@ManyToMany(() => Program)
|
@ManyToMany({
|
||||||
|
entity: () => Program,
|
||||||
|
deleteRule: 'cascade',
|
||||||
|
})
|
||||||
fallback = new Collection<Program>(this);
|
fallback = new Collection<Program>(this);
|
||||||
|
|
||||||
@Enum({ items: () => ChannelStreamModes, default: 'hls' })
|
@Enum({ items: () => ChannelStreamModes, default: 'hls' })
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ export class ChannelFillerShow {
|
|||||||
@ManyToOne({ primary: true, entity: () => FillerShow })
|
@ManyToOne({ primary: true, entity: () => FillerShow })
|
||||||
fillerShow!: Ref<FillerShow>;
|
fillerShow!: Ref<FillerShow>;
|
||||||
|
|
||||||
@ManyToOne({ primary: true, entity: () => Channel })
|
@ManyToOne({
|
||||||
|
primary: true,
|
||||||
|
entity: () => Channel,
|
||||||
|
deleteRule: 'cascade',
|
||||||
|
})
|
||||||
channel!: Ref<Channel>;
|
channel!: Ref<Channel>;
|
||||||
|
|
||||||
@Property()
|
@Property()
|
||||||
|
|||||||
@@ -237,7 +237,8 @@
|
|||||||
"default": "'hls'",
|
"default": "'hls'",
|
||||||
"enumItems": [
|
"enumItems": [
|
||||||
"hls",
|
"hls",
|
||||||
"hls_slower"
|
"hls_slower",
|
||||||
|
"mpegts"
|
||||||
],
|
],
|
||||||
"mappedType": "enum"
|
"mappedType": "enum"
|
||||||
}
|
}
|
||||||
@@ -578,6 +579,7 @@
|
|||||||
"uuid"
|
"uuid"
|
||||||
],
|
],
|
||||||
"referencedTableName": "channel",
|
"referencedTableName": "channel",
|
||||||
|
"deleteRule": "cascade",
|
||||||
"updateRule": "cascade"
|
"updateRule": "cascade"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
18
server/src/migrations/Migration20241014205231.ts
Normal file
18
server/src/migrations/Migration20241014205231.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Migration } from '@mikro-orm/migrations';
|
||||||
|
|
||||||
|
export class Migration20241014205231 extends Migration {
|
||||||
|
|
||||||
|
async up(): Promise<void> {
|
||||||
|
this.addSql('pragma foreign_keys = off;');
|
||||||
|
this.addSql('PRAGMA defer_foreign_keys = ON;');
|
||||||
|
this.addSql('create table `channel_filler_show__temp_alter` (`filler_show_uuid` text not null, `channel_uuid` text not null, `weight` integer not null, `cooldown` integer not null, constraint `channel_filler_show_filler_show_uuid_foreign` foreign key(`filler_show_uuid`) references `filler_show`(`uuid`) on update cascade, constraint `channel_filler_show_channel_uuid_foreign` foreign key(`channel_uuid`) references `channel`(`uuid`) on delete cascade on update cascade, primary key (`filler_show_uuid`, `channel_uuid`));');
|
||||||
|
this.addSql('insert into `channel_filler_show__temp_alter` select * from `channel_filler_show`;');
|
||||||
|
this.addSql('drop table `channel_filler_show`;');
|
||||||
|
this.addSql('alter table `channel_filler_show__temp_alter` rename to `channel_filler_show`;');
|
||||||
|
this.addSql('create index `channel_filler_show_filler_show_uuid_index` on `channel_filler_show` (`filler_show_uuid`);');
|
||||||
|
this.addSql('create index `channel_filler_show_channel_uuid_index` on `channel_filler_show` (`channel_uuid`);');
|
||||||
|
this.addSql('pragma foreign_keys = on;');
|
||||||
|
this.addSql('PRAGMA defer_foreign_keys = OFF;');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -144,16 +144,6 @@ export class TVGuideService {
|
|||||||
this.currentUpdateTime = now;
|
this.currentUpdateTime = now;
|
||||||
this.currentEndTime = now + guideDuration.asMilliseconds();
|
this.currentEndTime = now + guideDuration.asMilliseconds();
|
||||||
|
|
||||||
this.eventService.push({
|
|
||||||
type: 'xmltv',
|
|
||||||
message: `Started building tv-guide at = ${dayjs(now).format()}`,
|
|
||||||
module: 'xmltv',
|
|
||||||
detail: {
|
|
||||||
time: now,
|
|
||||||
},
|
|
||||||
level: 'info',
|
|
||||||
});
|
|
||||||
|
|
||||||
this.currentChannels = values(
|
this.currentChannels = values(
|
||||||
mapValues(
|
mapValues(
|
||||||
await this.channelDb.loadAllLineups(),
|
await this.channelDb.loadAllLineups(),
|
||||||
@@ -799,11 +789,10 @@ export class TVGuideService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async refreshXML() {
|
private async refreshXML() {
|
||||||
// const xmltvSettings = (await getSettings()).xmlTvSettings();
|
|
||||||
await this.xmltv.write(values(this.cachedGuide));
|
await this.xmltv.write(values(this.cachedGuide));
|
||||||
this.eventService.push({
|
this.eventService.push({
|
||||||
type: 'xmltv',
|
type: 'xmltv',
|
||||||
message: `XMLTV updated at server time = ${new Date().toISOString()}`,
|
message: `XMLTV updated at server time = ${dayjs().format()}`,
|
||||||
module: 'xmltv',
|
module: 'xmltv',
|
||||||
detail: {
|
detail: {
|
||||||
time: new Date().getTime(),
|
time: new Date().getTime(),
|
||||||
|
|||||||
Reference in New Issue
Block a user