mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-07 21:42:16 -07:00
Log TrackImport and TrackFileDeleted to History
This commit is contained in:
parent
ab9a9232cf
commit
729d1142b0
12 changed files with 94 additions and 44 deletions
|
@ -18,11 +18,11 @@ function getHeaderTitle(eventType) {
|
||||||
case 'downloadFailed':
|
case 'downloadFailed':
|
||||||
return 'Download Failed';
|
return 'Download Failed';
|
||||||
case 'downloadFolderImported':
|
case 'downloadFolderImported':
|
||||||
return 'Episode Imported';
|
return 'Track Imported';
|
||||||
case 'trackFileDeleted':
|
case 'trackFileDeleted':
|
||||||
return 'Episode File Deleted';
|
return 'Track File Deleted';
|
||||||
case 'trackFileRenamed':
|
case 'trackFileRenamed':
|
||||||
return 'Episode File Renamed';
|
return 'Track File Renamed';
|
||||||
default:
|
default:
|
||||||
return 'Unknown';
|
return 'Unknown';
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ class HistoryRow extends Component {
|
||||||
albumId,
|
albumId,
|
||||||
artist,
|
artist,
|
||||||
album,
|
album,
|
||||||
|
track,
|
||||||
language,
|
language,
|
||||||
quality,
|
quality,
|
||||||
eventType,
|
eventType,
|
||||||
|
@ -121,6 +122,14 @@ class HistoryRow extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name === 'trackTitle') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
{track.title}
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (name === 'language') {
|
if (name === 'language') {
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
|
@ -220,6 +229,7 @@ HistoryRow.propTypes = {
|
||||||
albumId: PropTypes.number,
|
albumId: PropTypes.number,
|
||||||
artist: PropTypes.object.isRequired,
|
artist: PropTypes.object.isRequired,
|
||||||
album: PropTypes.object,
|
album: PropTypes.object,
|
||||||
|
track: PropTypes.object,
|
||||||
language: PropTypes.object.isRequired,
|
language: PropTypes.object.isRequired,
|
||||||
quality: PropTypes.object.isRequired,
|
quality: PropTypes.object.isRequired,
|
||||||
eventType: PropTypes.string.isRequired,
|
eventType: PropTypes.string.isRequired,
|
||||||
|
@ -234,4 +244,10 @@ HistoryRow.propTypes = {
|
||||||
onMarkAsFailedPress: PropTypes.func.isRequired
|
onMarkAsFailedPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
HistoryRow.defaultProps = {
|
||||||
|
track: {
|
||||||
|
title: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default HistoryRow;
|
export default HistoryRow;
|
||||||
|
|
|
@ -37,6 +37,11 @@ export const defaultState = {
|
||||||
label: 'Album Title',
|
label: 'Album Title',
|
||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'trackTitle',
|
||||||
|
label: 'Track Title',
|
||||||
|
isVisible: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'language',
|
name: 'language',
|
||||||
label: 'Language',
|
label: 'Language',
|
||||||
|
|
|
@ -6,6 +6,7 @@ using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.History;
|
using NzbDrone.Core.History;
|
||||||
using Lidarr.Api.V3.Albums;
|
using Lidarr.Api.V3.Albums;
|
||||||
using Lidarr.Api.V3.Artist;
|
using Lidarr.Api.V3.Artist;
|
||||||
|
using Lidarr.Api.V3.Tracks;
|
||||||
using Lidarr.Http;
|
using Lidarr.Http;
|
||||||
using Lidarr.Http.Extensions;
|
using Lidarr.Http.Extensions;
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ namespace Lidarr.Api.V3.History
|
||||||
|
|
||||||
resource.Artist = model.Artist.ToResource();
|
resource.Artist = model.Artist.ToResource();
|
||||||
resource.Album = model.Album.ToResource();
|
resource.Album = model.Album.ToResource();
|
||||||
|
resource.Track = model.Track.ToResource();
|
||||||
|
|
||||||
if (model.Artist != null)
|
if (model.Artist != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,7 @@ using NzbDrone.Core.Languages;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using Lidarr.Api.V3.Albums;
|
using Lidarr.Api.V3.Albums;
|
||||||
using Lidarr.Api.V3.Artist;
|
using Lidarr.Api.V3.Artist;
|
||||||
|
using Lidarr.Api.V3.Tracks;
|
||||||
using Lidarr.Http.REST;
|
using Lidarr.Http.REST;
|
||||||
|
|
||||||
namespace Lidarr.Api.V3.History
|
namespace Lidarr.Api.V3.History
|
||||||
|
@ -13,6 +14,7 @@ namespace Lidarr.Api.V3.History
|
||||||
{
|
{
|
||||||
public int AlbumId { get; set; }
|
public int AlbumId { get; set; }
|
||||||
public int ArtistId { get; set; }
|
public int ArtistId { get; set; }
|
||||||
|
public int TrackId { get; set; }
|
||||||
public string SourceTitle { get; set; }
|
public string SourceTitle { get; set; }
|
||||||
public Language Language { get; set; }
|
public Language Language { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
|
@ -26,6 +28,7 @@ namespace Lidarr.Api.V3.History
|
||||||
|
|
||||||
public AlbumResource Album { get; set; }
|
public AlbumResource Album { get; set; }
|
||||||
public ArtistResource Artist { get; set; }
|
public ArtistResource Artist { get; set; }
|
||||||
|
public TrackResource Track { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HistoryResourceMapper
|
public static class HistoryResourceMapper
|
||||||
|
@ -40,6 +43,7 @@ namespace Lidarr.Api.V3.History
|
||||||
|
|
||||||
AlbumId = model.AlbumId,
|
AlbumId = model.AlbumId,
|
||||||
ArtistId = model.ArtistId,
|
ArtistId = model.ArtistId,
|
||||||
|
TrackId = model.TrackId,
|
||||||
SourceTitle = model.SourceTitle,
|
SourceTitle = model.SourceTitle,
|
||||||
Language = model.Language,
|
Language = model.Language,
|
||||||
Quality = model.Quality,
|
Quality = model.Quality,
|
||||||
|
|
|
@ -11,7 +11,7 @@ using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Core.History;
|
using NzbDrone.Core.History;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using NzbDrone.Core.Test.Qualities;
|
using NzbDrone.Core.Test.Qualities;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Core.Languages;
|
using NzbDrone.Core.Languages;
|
||||||
using NzbDrone.Core.Profiles.Languages;
|
using NzbDrone.Core.Profiles.Languages;
|
||||||
|
|
||||||
|
@ -54,23 +54,23 @@ namespace NzbDrone.Core.Test.HistoryTests
|
||||||
[Test]
|
[Test]
|
||||||
public void should_use_file_name_for_source_title_if_scene_name_is_null()
|
public void should_use_file_name_for_source_title_if_scene_name_is_null()
|
||||||
{
|
{
|
||||||
var series = Builder<Series>.CreateNew().Build();
|
var artist = Builder<Artist>.CreateNew().Build();
|
||||||
var episodes = Builder<Episode>.CreateListOfSize(1).Build().ToList();
|
var tracks = Builder<Track>.CreateListOfSize(1).Build().ToList();
|
||||||
var episodeFile = Builder<EpisodeFile>.CreateNew()
|
var trackFile = Builder<TrackFile>.CreateNew()
|
||||||
.With(f => f.SceneName = null)
|
.With(f => f.SceneName = null)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var localEpisode = new LocalEpisode
|
var localTrack = new LocalTrack
|
||||||
{
|
{
|
||||||
Series = series,
|
Artist = artist,
|
||||||
Episodes = episodes,
|
Tracks = tracks,
|
||||||
Path = @"C:\Test\Unsorted\Series.s01e01.mkv"
|
Path = @"C:\Test\Unsorted\Artist.01.Hymn.mp3"
|
||||||
};
|
};
|
||||||
|
|
||||||
Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, true, "sab", "abcd"));
|
Subject.Handle(new TrackImportedEvent(localTrack, trackFile, true, "sab", "abcd"));
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryRepository>()
|
Mocker.GetMock<IHistoryRepository>()
|
||||||
.Verify(v => v.Insert(It.Is<History.History>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localEpisode.Path))));
|
.Verify(v => v.Insert(It.Is<History.History>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localTrack.Path))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
src/NzbDrone.Core/Datastore/Migration/118_history_trackid.cs
Normal file
20
src/NzbDrone.Core/Datastore/Migration/118_history_trackid.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(118)]
|
||||||
|
public class history_trackid : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Alter.Table("History")
|
||||||
|
.AddColumn("TrackId").AsInt32().WithDefaultValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -113,7 +113,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
.Relationships.AutoMapICollectionOrComplexProperties()
|
.Relationships.AutoMapICollectionOrComplexProperties()
|
||||||
.For("Tracks")
|
.For("Tracks")
|
||||||
.LazyLoad(condition: parent => parent.Id > 0,
|
.LazyLoad(condition: parent => parent.Id > 0,
|
||||||
query: (db, parent) => db.Query<Track>().Where(c => c.ArtistId == parent.Id).ToList()) // TODO: Figure what the hell to do here
|
query: (db, parent) => db.Query<Track>().Where(c => c.TrackFileId == parent.Id).ToList()) // TODO: Figure what the hell to do here
|
||||||
.HasOne(file => file.Artist, file => file.ArtistId);
|
.HasOne(file => file.Artist, file => file.ArtistId);
|
||||||
|
|
||||||
Mapper.Entity<Track>().RegisterModel("Tracks")
|
Mapper.Entity<Track>().RegisterModel("Tracks")
|
||||||
|
|
|
@ -15,7 +15,8 @@ namespace NzbDrone.Core.History
|
||||||
{
|
{
|
||||||
Data = new Dictionary<string, string>();
|
Data = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int TrackId { get; set; }
|
||||||
public int AlbumId { get; set; }
|
public int AlbumId { get; set; }
|
||||||
public int ArtistId { get; set; }
|
public int ArtistId { get; set; }
|
||||||
public string SourceTitle { get; set; }
|
public string SourceTitle { get; set; }
|
||||||
|
@ -23,6 +24,7 @@ namespace NzbDrone.Core.History
|
||||||
public DateTime Date { get; set; }
|
public DateTime Date { get; set; }
|
||||||
public Album Album { get; set; }
|
public Album Album { get; set; }
|
||||||
public Artist Artist { get; set; }
|
public Artist Artist { get; set; }
|
||||||
|
public Track Track { get; set; }
|
||||||
public HistoryEventType EventType { get; set; }
|
public HistoryEventType EventType { get; set; }
|
||||||
public Dictionary<string, string> Data { get; set; }
|
public Dictionary<string, string> Data { get; set; }
|
||||||
public Language Language { get; set; }
|
public Language Language { get; set; }
|
||||||
|
@ -38,6 +40,6 @@ namespace NzbDrone.Core.History
|
||||||
SeriesFolderImported = 2,
|
SeriesFolderImported = 2,
|
||||||
DownloadFolderImported = 3,
|
DownloadFolderImported = 3,
|
||||||
DownloadFailed = 4,
|
DownloadFailed = 4,
|
||||||
EpisodeFileDeleted = 5
|
TrackFileDeleted = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,8 @@ namespace NzbDrone.Core.History
|
||||||
protected override SortBuilder<History> GetPagedQuery(QueryBuilder<History> query, PagingSpec<History> pagingSpec)
|
protected override SortBuilder<History> GetPagedQuery(QueryBuilder<History> query, PagingSpec<History> pagingSpec)
|
||||||
{
|
{
|
||||||
var baseQuery = query.Join<History, Artist>(JoinType.Inner, h => h.Artist, (h, s) => h.ArtistId == s.Id)
|
var baseQuery = query.Join<History, Artist>(JoinType.Inner, h => h.Artist, (h, s) => h.ArtistId == s.Id)
|
||||||
.Join<History, Album>(JoinType.Inner, h => h.Album, (h, e) => h.AlbumId == e.Id);
|
.Join<History, Album>(JoinType.Inner, h => h.Album, (h, e) => h.AlbumId == e.Id)
|
||||||
|
.Join<History, Track>(JoinType.Left, h => h.Track, (h, e) => h.TrackId == e.Id);
|
||||||
|
|
||||||
return base.GetPagedQuery(baseQuery, pagingSpec);
|
return base.GetPagedQuery(baseQuery, pagingSpec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,9 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
public class HistoryService : IHistoryService,
|
public class HistoryService : IHistoryService,
|
||||||
IHandle<AlbumGrabbedEvent>,
|
IHandle<AlbumGrabbedEvent>,
|
||||||
IHandle<EpisodeImportedEvent>,
|
IHandle<TrackImportedEvent>,
|
||||||
IHandle<DownloadFailedEvent>,
|
IHandle<DownloadFailedEvent>,
|
||||||
IHandle<EpisodeFileDeletedEvent>,
|
IHandle<TrackFileDeletedEvent>,
|
||||||
IHandle<ArtistDeletedEvent>
|
IHandle<ArtistDeletedEvent>
|
||||||
{
|
{
|
||||||
private readonly IHistoryRepository _historyRepository;
|
private readonly IHistoryRepository _historyRepository;
|
||||||
|
@ -74,14 +74,13 @@ namespace NzbDrone.Core.History
|
||||||
return _historyRepository.FindByDownloadId(downloadId);
|
return _historyRepository.FindByDownloadId(downloadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Used for Sonarr, not Lidarr")]
|
private string FindDownloadId(TrackImportedEvent trackedDownload)
|
||||||
private string FindDownloadId(EpisodeImportedEvent trackedDownload)
|
|
||||||
{
|
{
|
||||||
_logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedEpisode.Path);
|
_logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedTrack.Path);
|
||||||
|
|
||||||
var albumIds = trackedDownload.EpisodeInfo.Episodes.Select(c => c.Id).ToList();
|
var albumIds = trackedDownload.TrackInfo.Tracks.Select(c => c.AlbumId).ToList();
|
||||||
|
|
||||||
var allHistory = _historyRepository.FindDownloadHistory(trackedDownload.EpisodeInfo.Series.Id, trackedDownload.ImportedEpisode.Quality);
|
var allHistory = _historyRepository.FindDownloadHistory(trackedDownload.TrackInfo.Artist.Id, trackedDownload.ImportedTrack.Quality);
|
||||||
|
|
||||||
|
|
||||||
//Find download related items for these episdoes
|
//Find download related items for these episdoes
|
||||||
|
@ -97,7 +96,7 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
if (stillDownloading.Any())
|
if (stillDownloading.Any())
|
||||||
{
|
{
|
||||||
foreach (var matchingHistory in trackedDownload.EpisodeInfo.Episodes.Select(e => stillDownloading.Where(c => c.AlbumId == e.Id).ToList()))
|
foreach (var matchingHistory in trackedDownload.TrackInfo.Tracks.Select(e => stillDownloading.Where(c => c.AlbumId == e.AlbumId).ToList()))
|
||||||
{
|
{
|
||||||
if (matchingHistory.Count != 1)
|
if (matchingHistory.Count != 1)
|
||||||
{
|
{
|
||||||
|
@ -165,8 +164,7 @@ namespace NzbDrone.Core.History
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Used for Sonarr, not Lidarr")]
|
public void Handle(TrackImportedEvent message)
|
||||||
public void Handle(EpisodeImportedEvent message)
|
|
||||||
{
|
{
|
||||||
if (!message.NewDownload)
|
if (!message.NewDownload)
|
||||||
{
|
{
|
||||||
|
@ -180,24 +178,25 @@ namespace NzbDrone.Core.History
|
||||||
downloadId = FindDownloadId(message);
|
downloadId = FindDownloadId(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var episode in message.EpisodeInfo.Episodes)
|
foreach (var track in message.TrackInfo.Tracks)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new History
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.DownloadFolderImported,
|
EventType = HistoryEventType.DownloadFolderImported,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.EpisodeInfo.Quality,
|
Quality = message.TrackInfo.Quality,
|
||||||
SourceTitle = message.ImportedEpisode.SceneName ?? Path.GetFileNameWithoutExtension(message.EpisodeInfo.Path),
|
SourceTitle = message.ImportedTrack.SceneName ?? Path.GetFileNameWithoutExtension(message.TrackInfo.Path),
|
||||||
ArtistId = message.ImportedEpisode.SeriesId,
|
ArtistId = message.ImportedTrack.ArtistId,
|
||||||
AlbumId = episode.Id,
|
AlbumId = message.ImportedTrack.AlbumId,
|
||||||
|
TrackId = track.Id,
|
||||||
DownloadId = downloadId,
|
DownloadId = downloadId,
|
||||||
Language = message.EpisodeInfo.Language
|
Language = message.TrackInfo.Language
|
||||||
};
|
};
|
||||||
|
|
||||||
//Won't have a value since we publish this event before saving to DB.
|
//Won't have a value since we publish this event before saving to DB.
|
||||||
//history.Data.Add("FileId", message.ImportedEpisode.Id.ToString());
|
//history.Data.Add("FileId", message.ImportedEpisode.Id.ToString());
|
||||||
history.Data.Add("DroppedPath", message.EpisodeInfo.Path);
|
history.Data.Add("DroppedPath", message.TrackInfo.Path);
|
||||||
history.Data.Add("ImportedPath", Path.Combine(message.EpisodeInfo.Series.Path, message.ImportedEpisode.RelativePath));
|
history.Data.Add("ImportedPath", Path.Combine(message.TrackInfo.Artist.Path, message.ImportedTrack.RelativePath));
|
||||||
history.Data.Add("DownloadClient", message.DownloadClient);
|
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||||
|
|
||||||
_historyRepository.Insert(history);
|
_historyRepository.Insert(history);
|
||||||
|
@ -227,25 +226,25 @@ namespace NzbDrone.Core.History
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Used for Sonarr, not Lidarr")]
|
public void Handle(TrackFileDeletedEvent message)
|
||||||
public void Handle(EpisodeFileDeletedEvent message)
|
|
||||||
{
|
{
|
||||||
if (message.Reason == DeleteMediaFileReason.NoLinkedEpisodes)
|
if (message.Reason == DeleteMediaFileReason.NoLinkedEpisodes)
|
||||||
{
|
{
|
||||||
_logger.Debug("Removing episode file from DB as part of cleanup routine, not creating history event.");
|
_logger.Debug("Removing track file from DB as part of cleanup routine, not creating history event.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var episode in message.EpisodeFile.Episodes.Value)
|
foreach (var track in message.TrackFile.Tracks.Value)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new History
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.EpisodeFileDeleted,
|
EventType = HistoryEventType.TrackFileDeleted,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.EpisodeFile.Quality,
|
Quality = message.TrackFile.Quality,
|
||||||
SourceTitle = message.EpisodeFile.Path,
|
SourceTitle = message.TrackFile.Path,
|
||||||
ArtistId = message.EpisodeFile.SeriesId,
|
ArtistId = message.TrackFile.ArtistId,
|
||||||
AlbumId = episode.Id,
|
AlbumId = message.TrackFile.AlbumId,
|
||||||
|
TrackId = track.Id,
|
||||||
};
|
};
|
||||||
|
|
||||||
history.Data.Add("Reason", message.Reason.ToString());
|
history.Data.Add("Reason", message.Reason.ToString());
|
||||||
|
|
|
@ -293,6 +293,7 @@
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Datastore\Migration\105_rename_torrent_downloadstation.cs" />
|
<Compile Include="Datastore\Migration\105_rename_torrent_downloadstation.cs" />
|
||||||
<Compile Include="Datastore\Migration\111_create_language_profiles.cs" />
|
<Compile Include="Datastore\Migration\111_create_language_profiles.cs" />
|
||||||
|
<Compile Include="Datastore\Migration\118_history_trackid.cs" />
|
||||||
<Compile Include="Datastore\Migration\117_artist_links.cs" />
|
<Compile Include="Datastore\Migration\117_artist_links.cs" />
|
||||||
<Compile Include="Datastore\Migration\116_change_drone_factory_variable_name.cs" />
|
<Compile Include="Datastore\Migration\116_change_drone_factory_variable_name.cs" />
|
||||||
<Compile Include="Datastore\Migration\115_remove_tv_naming.cs" />
|
<Compile Include="Datastore\Migration\115_remove_tv_naming.cs" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue