feat: add fnOS packaging, storage workflows and release pipeline
This commit is contained in:
@@ -8,8 +8,16 @@
|
||||
|
||||
public string Key { get; set; }
|
||||
|
||||
public string CookieId { get; set; }
|
||||
|
||||
public int Total { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public int Status { get; set; }
|
||||
|
||||
public int StatusCode { get; set; }
|
||||
|
||||
public string StatusMessage { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public sealed class DouyinFollowLookupRequest
|
||||
{
|
||||
public string CookieId { get; set; }
|
||||
|
||||
public string DouyinNo { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DouyinFollowLookupResult
|
||||
{
|
||||
public string Query { get; set; }
|
||||
|
||||
public List<DouyinFollowCandidate> Candidates { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class DouyinFollowCandidate
|
||||
{
|
||||
public string SecUid { get; set; }
|
||||
|
||||
public string UperId { get; set; }
|
||||
|
||||
public string DouyinNo { get; set; }
|
||||
|
||||
public string UniqueId { get; set; }
|
||||
|
||||
public string ShortId { get; set; }
|
||||
|
||||
public string UperName { get; set; }
|
||||
|
||||
public string UperAvatar { get; set; }
|
||||
|
||||
public string Signature { get; set; }
|
||||
|
||||
public string Enterprise { get; set; }
|
||||
|
||||
public long FollowerCount { get; set; }
|
||||
|
||||
public bool ExactMatch { get; set; }
|
||||
|
||||
public bool AlreadyExists { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public enum DouyinLiveStatusState
|
||||
{
|
||||
Unknown = 0,
|
||||
Offline = 1,
|
||||
Live = 2
|
||||
}
|
||||
|
||||
public sealed class FollowLiveMonitorUpdateDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
|
||||
public sealed class FollowLiveStatusRefreshDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
public sealed class FollowLiveStatusQueryDto
|
||||
{
|
||||
public List<string> Ids { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class FollowLiveStatusDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public bool LiveMonitorEnabled { get; set; }
|
||||
public DouyinLiveStatusState LiveStatus { get; set; }
|
||||
public string LiveRoomId { get; set; }
|
||||
public string LiveWebRid { get; set; }
|
||||
public string LiveTitle { get; set; }
|
||||
public string LiveRoomUrl { get; set; }
|
||||
public DateTime? LiveCheckedAt { get; set; }
|
||||
public DateTime? LiveStatusUpdatedAt { get; set; }
|
||||
public DateTime? LiveStartedAt { get; set; }
|
||||
public string LiveCheckError { get; set; }
|
||||
public bool LiveStatusStale { get; set; }
|
||||
public bool LiveEmailNotificationEnabled { get; set; }
|
||||
public DateTime? LastLiveNotifiedAt { get; set; }
|
||||
public string LastLiveNotificationError { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DouyinLiveStatusProbe
|
||||
{
|
||||
public DouyinLiveStatusState Status { get; set; }
|
||||
public string RoomId { get; set; }
|
||||
public string WebRid { get; set; }
|
||||
public string Title { get; set; }
|
||||
public DateTime? StartedAt { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,11 @@
|
||||
public string? Title { get; set; }
|
||||
|
||||
public string? Author { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 博主 UID 精确筛选。用于从关注列表直达该博主的已同步视频。
|
||||
/// </summary>
|
||||
public string? AuthorId { get; set; }
|
||||
//public string? Name { get; set; }
|
||||
|
||||
public string? ViedoType { get; set; }
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public enum EmailSecurityMode
|
||||
{
|
||||
None = 0,
|
||||
StartTls = 1,
|
||||
SslOnConnect = 2
|
||||
}
|
||||
|
||||
public sealed class EmailNotificationSettingsDto
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string Host { get; set; }
|
||||
public int Port { get; set; } = 465;
|
||||
public EmailSecurityMode SecurityMode { get; set; } = EmailSecurityMode.SslOnConnect;
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool HasPassword { get; set; }
|
||||
public string FromAddress { get; set; }
|
||||
public string FromName { get; set; }
|
||||
public string Recipients { get; set; }
|
||||
public DateTime? LastTestedAt { get; set; }
|
||||
public string LastTestMessage { get; set; }
|
||||
}
|
||||
|
||||
public sealed class FollowLiveEmailUpdateDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using System.Net;
|
||||
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public enum MediaDownloadFailureKind
|
||||
{
|
||||
None = 0,
|
||||
SourceUnavailable = 1,
|
||||
SourceForbidden = 2,
|
||||
SourceUnauthorized = 3,
|
||||
SourceNotFound = 4,
|
||||
SourceRateLimited = 5,
|
||||
SourceInvalidContent = 6,
|
||||
StorageUnavailable = 7,
|
||||
IntegrityCheckFailed = 8,
|
||||
Cancelled = 9
|
||||
}
|
||||
|
||||
public sealed class MediaDownloadResult
|
||||
{
|
||||
public bool Success { get; init; }
|
||||
public string ActualSavePath { get; init; }
|
||||
public MediaDownloadFailureKind FailureKind { get; init; }
|
||||
public int? HttpStatusCode { get; init; }
|
||||
public string SourceHost { get; init; }
|
||||
public int AttemptedUrlCount { get; init; }
|
||||
public DateTime? RetryAfter { get; init; }
|
||||
public string Message { get; init; }
|
||||
|
||||
public void Deconstruct(out bool success, out string actualSavePath)
|
||||
{
|
||||
success = Success;
|
||||
actualSavePath = ActualSavePath;
|
||||
}
|
||||
|
||||
public Exception ToException() => FailureKind switch
|
||||
{
|
||||
MediaDownloadFailureKind.StorageUnavailable => new MediaStorageException(Message ?? "媒体存储写入失败。"),
|
||||
MediaDownloadFailureKind.IntegrityCheckFailed => new MediaIntegrityException(Message ?? "媒体完整性校验失败。"),
|
||||
MediaDownloadFailureKind.Cancelled => new OperationCanceledException(Message ?? "媒体下载已取消。"),
|
||||
_ => new MediaSourceException(FailureKind, Message ?? "媒体来源不可用。", HttpStatusCode, SourceHost, RetryAfter)
|
||||
};
|
||||
|
||||
public static MediaDownloadResult Succeeded(string path, string host, int attempted) => new()
|
||||
{
|
||||
Success = true,
|
||||
ActualSavePath = path,
|
||||
SourceHost = host,
|
||||
AttemptedUrlCount = attempted
|
||||
};
|
||||
}
|
||||
|
||||
public sealed class MediaSourceException : Exception
|
||||
{
|
||||
public MediaSourceException(
|
||||
MediaDownloadFailureKind kind,
|
||||
string message,
|
||||
int? statusCode = null,
|
||||
string sourceHost = null,
|
||||
DateTime? retryAfter = null,
|
||||
Exception innerException = null) : base(message, innerException)
|
||||
{
|
||||
FailureKind = kind;
|
||||
StatusCode = statusCode;
|
||||
SourceHost = sourceHost;
|
||||
RetryAfter = retryAfter;
|
||||
}
|
||||
|
||||
public MediaDownloadFailureKind FailureKind { get; }
|
||||
public int? StatusCode { get; }
|
||||
public string SourceHost { get; }
|
||||
public DateTime? RetryAfter { get; }
|
||||
}
|
||||
|
||||
public sealed class MediaStorageException : IOException
|
||||
{
|
||||
public MediaStorageException(string message, Exception innerException = null) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
public sealed class MediaIntegrityException : IOException
|
||||
{
|
||||
public MediaIntegrityException(string message, Exception innerException = null) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
public enum SourceFailureDisposition
|
||||
{
|
||||
Continue = 0,
|
||||
WaitForSource = 1,
|
||||
RequiresAuthorization = 2
|
||||
}
|
||||
|
||||
public sealed class SourceAccessDecision
|
||||
{
|
||||
public bool Allowed { get; init; }
|
||||
public bool IsProbe { get; init; }
|
||||
public string Message { get; init; }
|
||||
public DateTime? RetryAt { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using dy.net.model.entity;
|
||||
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public enum OpenListDirectoryRepairStatus
|
||||
{
|
||||
Queued = 0,
|
||||
Scanning = 1,
|
||||
AwaitingConfirmation = 2,
|
||||
Cleaning = 3,
|
||||
Completed = 4,
|
||||
PartiallyFailed = 5,
|
||||
Cancelled = 6,
|
||||
Paused = 7
|
||||
}
|
||||
|
||||
public enum OpenListDirectoryRepairItemStatus
|
||||
{
|
||||
Pending = 0,
|
||||
Inspecting = 1,
|
||||
EmptyConfirmed = 2,
|
||||
SkippedNonEmpty = 3,
|
||||
Deleting = 4,
|
||||
Deleted = 5,
|
||||
Failed = 6,
|
||||
Missing = 7
|
||||
}
|
||||
|
||||
public sealed class OpenListDirectoryRepairPreflightRequest
|
||||
{
|
||||
public string LogicalPath { get; set; } = "/collect/Kk";
|
||||
}
|
||||
|
||||
public sealed class OpenListDirectoryRepairPreflightResult
|
||||
{
|
||||
public bool CanStart { get; set; }
|
||||
public string RequestedPath { get; set; }
|
||||
public string CanonicalPath { get; set; }
|
||||
public string CandidatePattern { get; set; }
|
||||
public string ConfigurationFingerprint { get; set; }
|
||||
public int CandidateCount { get; set; }
|
||||
public List<string> Errors { get; set; } = new();
|
||||
public List<string> Warnings { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class CreateOpenListDirectoryRepairRequest
|
||||
{
|
||||
public string LogicalPath { get; set; } = "/collect/Kk";
|
||||
public string ConfigurationFingerprint { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ConfirmOpenListDirectoryRepairRequest
|
||||
{
|
||||
public string ConfirmationToken { get; set; }
|
||||
}
|
||||
|
||||
public sealed class OpenListDirectoryRepairTaskDetail
|
||||
{
|
||||
public OpenListDirectoryRepairTask Task { get; set; }
|
||||
public string StatusText { get; set; }
|
||||
public string ConfirmationToken { get; set; }
|
||||
public bool CanConfirmCleanup { get; set; }
|
||||
public bool CanCancel { get; set; }
|
||||
public bool CanResume { get; set; }
|
||||
public bool CanRetryFailed { get; set; }
|
||||
}
|
||||
|
||||
public sealed class OpenListDirectoryRepairItemPageRequest
|
||||
{
|
||||
public int PageIndex { get; set; } = 1;
|
||||
public int PageSize { get; set; } = 20;
|
||||
public OpenListDirectoryRepairItemStatus? Status { get; set; }
|
||||
public string Keyword { get; set; }
|
||||
}
|
||||
|
||||
public sealed class OpenListDirectoryRepairItemPage
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public List<OpenListDirectoryRepairItem> Items { get; set; } = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class OpenListSettingsDto
|
||||
{
|
||||
public StorageType StorageType { get; set; }
|
||||
public string Endpoint { get; set; }
|
||||
public string BasePath { get; set; }
|
||||
public string LocalStagingPath { get; set; }
|
||||
public string SourcePath { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool HasPassword { get; set; }
|
||||
public DateTime? LastTestedAt { get; set; }
|
||||
public string LastTestMessage { get; set; }
|
||||
public bool RequiresCutover { get; set; }
|
||||
public int LegacyWebDavRecordCount { get; set; }
|
||||
public bool SuggestedFromLegacy { get; set; }
|
||||
}
|
||||
|
||||
public class OpenListTestRequest
|
||||
{
|
||||
public string Endpoint { get; set; }
|
||||
public string BasePath { get; set; }
|
||||
public string LocalStagingPath { get; set; }
|
||||
public string SourcePath { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
||||
public sealed class OpenListDirectoryRequest : OpenListTestRequest
|
||||
{
|
||||
public string Path { get; set; }
|
||||
}
|
||||
|
||||
public sealed class OpenListDirectoryItemDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Path { get; set; }
|
||||
}
|
||||
|
||||
public sealed class OpenListDirectoryListDto
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public bool CanWrite { get; set; }
|
||||
public List<OpenListDirectoryItemDto> Directories { get; set; } = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public enum OpenListTransferStatus
|
||||
{
|
||||
Queued = 0,
|
||||
WaitingForSource = 1,
|
||||
Copying = 2,
|
||||
Verifying = 3,
|
||||
Promoting = 4,
|
||||
WaitingRetry = 5,
|
||||
Succeeded = 6,
|
||||
Failed = 7,
|
||||
Cancelled = 8
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using dy.net.model.entity;
|
||||
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public enum StorageMigrationTaskStatus
|
||||
{
|
||||
Queued = 0,
|
||||
Running = 1,
|
||||
Paused = 2,
|
||||
Completed = 3,
|
||||
PartiallyFailed = 4,
|
||||
Cancelled = 5,
|
||||
Cleaning = 6,
|
||||
Cleaned = 7,
|
||||
RolledBack = 8
|
||||
}
|
||||
|
||||
public enum StorageMigrationItemStage
|
||||
{
|
||||
Pending = 0,
|
||||
Uploading = 1,
|
||||
Verifying = 2,
|
||||
Committing = 3,
|
||||
Succeeded = 4,
|
||||
SucceededWithWarnings = 5,
|
||||
Failed = 6,
|
||||
Cleaned = 7,
|
||||
RolledBack = 8,
|
||||
RecordRemoved = 9
|
||||
}
|
||||
|
||||
public sealed class StorageMigrationPreflightRequest
|
||||
{
|
||||
public bool VerifyCapabilities { get; set; } = true;
|
||||
}
|
||||
|
||||
public sealed class StorageMigrationPreflightResult
|
||||
{
|
||||
public bool CanStart { get; set; }
|
||||
public string ConfigurationFingerprint { get; set; }
|
||||
public int RecordCount { get; set; }
|
||||
public int LocalRecordCount { get; set; }
|
||||
public int LegacyWebDavRecordCount { get; set; }
|
||||
public int AdoptableCount { get; set; }
|
||||
public int TransferRequiredCount { get; set; }
|
||||
public int ReadableFileCount { get; set; }
|
||||
public int MissingFileCount { get; set; }
|
||||
public long TotalBytes { get; set; }
|
||||
public int InvalidCookieCount { get; set; }
|
||||
public int MissingTargetPathCount { get; set; }
|
||||
public int ConflictCount { get; set; }
|
||||
public string Capacity { get; set; } = "unknown";
|
||||
public List<string> Errors { get; set; } = new();
|
||||
public List<string> Warnings { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class CreateStorageMigrationRequest
|
||||
{
|
||||
public int Concurrency { get; set; } = 1;
|
||||
public string ConfigurationFingerprint { get; set; }
|
||||
}
|
||||
|
||||
public sealed class StorageMigrationItemPageRequest
|
||||
{
|
||||
public int PageIndex { get; set; } = 1;
|
||||
public int PageSize { get; set; } = 20;
|
||||
public StorageMigrationItemStage? Stage { get; set; }
|
||||
}
|
||||
|
||||
public sealed class StorageMigrationTaskDetail
|
||||
{
|
||||
public StorageMigrationTask Task { get; set; }
|
||||
public string StatusText { get; set; }
|
||||
public string CurrentFile { get; set; }
|
||||
public bool CanPause { get; set; }
|
||||
public bool CanResume { get; set; }
|
||||
public bool CanCancel { get; set; }
|
||||
public bool CanRetryFailed { get; set; }
|
||||
public bool CanCleanup { get; set; }
|
||||
public bool CanRollback { get; set; }
|
||||
public bool CanArchive { get; set; }
|
||||
}
|
||||
|
||||
public sealed class StorageRecordInventory
|
||||
{
|
||||
public StorageType CurrentStorageType { get; set; }
|
||||
public int TotalRecordCount { get; set; }
|
||||
public int LocalRecordCount { get; set; }
|
||||
public int WebDavRecordCount { get; set; }
|
||||
public int OpenListRecordCount { get; set; }
|
||||
public int CurrentStorageRecordCount { get; set; }
|
||||
public int OtherStorageRecordCount { get; set; }
|
||||
public long LocalDeclaredBytes { get; set; }
|
||||
public long WebDavDeclaredBytes { get; set; }
|
||||
public long OpenListDeclaredBytes { get; set; }
|
||||
public bool AllRecordsOnCurrentStorage => TotalRecordCount == CurrentStorageRecordCount;
|
||||
}
|
||||
|
||||
public sealed class StorageMigrationArchiveResult
|
||||
{
|
||||
public int ArchivedCount { get; set; }
|
||||
public int RequiresCleanupCount { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public sealed class StorageMigrationItemPage
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public List<StorageMigrationItem> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class FailedMigrationRecordPreview
|
||||
{
|
||||
public bool CanExecute { get; set; }
|
||||
public int ActiveMigrationCount { get; set; }
|
||||
public int FailedItemCount { get; set; }
|
||||
public int DistinctVideoCount { get; set; }
|
||||
public int EligibleRecordCount { get; set; }
|
||||
public int AlreadyMissingCount { get; set; }
|
||||
public int ChangedRecordCount { get; set; }
|
||||
public int PermanentlyExcludedCount { get; set; }
|
||||
public int InvalidSnapshotCount { get; set; }
|
||||
public string ConfirmationToken { get; set; }
|
||||
public List<string> Errors { get; set; } = new();
|
||||
public List<string> Warnings { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class RemoveFailedMigrationRecordsRequest
|
||||
{
|
||||
public string ConfirmationToken { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RemoveFailedMigrationRecordsResult
|
||||
{
|
||||
public int DeletedRecordCount { get; set; }
|
||||
public int AlreadyMissingCount { get; set; }
|
||||
public int RemovedItemCount { get; set; }
|
||||
public int AffectedTaskCount { get; set; }
|
||||
public int SkippedChangedCount { get; set; }
|
||||
public int SkippedExcludedCount { get; set; }
|
||||
public int InvalidSnapshotCount { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
/// <summary>
|
||||
/// 媒体实际保存的位置。数值 0 必须保留为本地存储,以兼容历史数据库记录。
|
||||
/// </summary>
|
||||
public enum StorageType
|
||||
{
|
||||
Local = 0,
|
||||
WebDav = 1,
|
||||
OpenList = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StorageType 扩展方法。
|
||||
/// </summary>
|
||||
public static class StorageTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断是否为远程存储(WebDAV 或 OpenList),与本地存储相对。
|
||||
/// </summary>
|
||||
public static bool IsRemote(this StorageType type) =>
|
||||
type is StorageType.WebDav or StorageType.OpenList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
using dy.net.model.entity;
|
||||
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public enum VideoTaskType
|
||||
{
|
||||
Sync = 0,
|
||||
Redownload = 1,
|
||||
ExclusionRestore = 2,
|
||||
StorageMigration = 3,
|
||||
StorageMaintenance = 4
|
||||
}
|
||||
|
||||
public enum VideoTaskTrigger
|
||||
{
|
||||
Scheduled = 0,
|
||||
Manual = 1,
|
||||
UserAction = 2,
|
||||
UpgradeRecovery = 3
|
||||
}
|
||||
|
||||
public enum VideoTaskStatus
|
||||
{
|
||||
Queued = 0,
|
||||
Running = 1,
|
||||
WaitingForStorage = 2,
|
||||
Completed = 3,
|
||||
PartiallyFailed = 4,
|
||||
Failed = 5,
|
||||
Interrupted = 6,
|
||||
Paused = 7,
|
||||
Cancelled = 8,
|
||||
Cleaning = 9,
|
||||
Cleaned = 10,
|
||||
RolledBack = 11,
|
||||
WaitingForSource = 12,
|
||||
Scanning = 13,
|
||||
AwaitingConfirmation = 14
|
||||
}
|
||||
|
||||
public enum VideoTaskItemStage
|
||||
{
|
||||
Pending = 0,
|
||||
Downloading = 1,
|
||||
Verifying = 2,
|
||||
Committing = 3,
|
||||
Succeeded = 4,
|
||||
SucceededWithWarnings = 5,
|
||||
Failed = 6,
|
||||
Skipped = 7,
|
||||
WaitingForStorage = 8,
|
||||
Cleaned = 9,
|
||||
RolledBack = 10,
|
||||
Cancelled = 11,
|
||||
WaitingForSource = 12,
|
||||
RecordRemoved = 13,
|
||||
Inspecting = 14,
|
||||
EmptyConfirmed = 15,
|
||||
SkippedNonEmpty = 16
|
||||
}
|
||||
|
||||
public enum VideoTaskErrorType
|
||||
{
|
||||
None = 0,
|
||||
SourceUnavailable = 1,
|
||||
CookieInvalid = 2,
|
||||
StorageUnavailable = 3,
|
||||
IntegrityCheckFailed = 4,
|
||||
DatabaseCommitFailed = 5,
|
||||
Interrupted = 6,
|
||||
ConfigurationChanged = 7,
|
||||
Excluded = 8,
|
||||
Unknown = 9,
|
||||
SourceForbidden = 10,
|
||||
SourceRateLimited = 11
|
||||
}
|
||||
|
||||
public enum VideoTaskSkipReason
|
||||
{
|
||||
None = 0,
|
||||
AlreadyExists = 1,
|
||||
Deduplicated = 2,
|
||||
PermanentlyExcluded = 3,
|
||||
ConfigurationExcluded = 4,
|
||||
NoMediaSource = 5
|
||||
}
|
||||
|
||||
public enum MediaStorageHealthStatus
|
||||
{
|
||||
Healthy = 0,
|
||||
Unavailable = 1
|
||||
}
|
||||
|
||||
public sealed class VideoTaskPageRequest : PageRequestDto
|
||||
{
|
||||
public VideoTaskType? Type { get; set; }
|
||||
public VideoTaskStatus? Status { get; set; }
|
||||
public VideoTaskTrigger? Trigger { get; set; }
|
||||
public string Keyword { get; set; }
|
||||
public DateTime? From { get; set; }
|
||||
public DateTime? To { get; set; }
|
||||
}
|
||||
|
||||
public sealed class VideoTaskItemPageRequest : PageRequestDto
|
||||
{
|
||||
public VideoTaskItemStage? Stage { get; set; }
|
||||
public VideoTaskErrorType? ErrorType { get; set; }
|
||||
public string Keyword { get; set; }
|
||||
public bool IncludeSkipped { get; set; }
|
||||
}
|
||||
|
||||
public sealed class VideoTaskListPage
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public List<UnifiedVideoTaskDto> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class VideoTaskItemPage
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public List<UnifiedVideoTaskItemDto> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class UnifiedVideoTaskDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public VideoTaskType Type { get; set; }
|
||||
public VideoTaskTrigger Trigger { get; set; }
|
||||
public VideoTaskStatus Status { get; set; }
|
||||
public string Title { get; set; }
|
||||
public VideoTypeEnum? VideoType { get; set; }
|
||||
public StorageType StorageType { get; set; }
|
||||
public int TotalCount { get; set; }
|
||||
public int PendingCount { get; set; }
|
||||
public int RunningCount { get; set; }
|
||||
public int SuccessCount { get; set; }
|
||||
public int WarningCount { get; set; }
|
||||
public int FailedCount { get; set; }
|
||||
public int SkippedCount { get; set; }
|
||||
public int RemovedCount { get; set; }
|
||||
public string CurrentFile { get; set; }
|
||||
public string ErrorMessage { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
public DateTime? CompletedAt { get; set; }
|
||||
public List<string> AvailableActions { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class UnifiedVideoTaskItemDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string TaskId { get; set; }
|
||||
public string VideoId { get; set; }
|
||||
public string AwemeId { get; set; }
|
||||
public string CookieName { get; set; }
|
||||
public VideoTypeEnum? VideoType { get; set; }
|
||||
public string VideoTitle { get; set; }
|
||||
public string Author { get; set; }
|
||||
public string TargetPath { get; set; }
|
||||
public VideoTaskItemStage Stage { get; set; }
|
||||
public VideoTaskErrorType ErrorType { get; set; }
|
||||
public VideoTaskSkipReason SkipReason { get; set; }
|
||||
public int Attempts { get; set; }
|
||||
public long ExpectedLength { get; set; }
|
||||
public long ActualLength { get; set; }
|
||||
public string ErrorMessage { get; set; }
|
||||
public string WarningMessage { get; set; }
|
||||
public string SourceHost { get; set; }
|
||||
public int? HttpStatusCode { get; set; }
|
||||
public DateTime? RetryAfter { get; set; }
|
||||
public string ExclusionId { get; set; }
|
||||
public DateTime? ExclusionReleasedAt { get; set; }
|
||||
public string RelatedTaskId { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
public DateTime? CompletedAt { get; set; }
|
||||
public bool CanRetry { get; set; }
|
||||
public bool CanRetryCleanup { get; set; }
|
||||
public string CleanupError { get; set; }
|
||||
public bool CanUnexclude { get; set; }
|
||||
}
|
||||
|
||||
public sealed class VideoTaskSummaryDto
|
||||
{
|
||||
public int Queued { get; set; }
|
||||
public int Running { get; set; }
|
||||
public int WaitingForStorage { get; set; }
|
||||
public int WaitingForSource { get; set; }
|
||||
public int Failed { get; set; }
|
||||
public int Completed { get; set; }
|
||||
public MediaStorageHealth StorageHealth { get; set; }
|
||||
public List<DouyinSourceHealthDto> SourceHealth { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class DouyinSourceHealthDto
|
||||
{
|
||||
public string CookieId { get; set; }
|
||||
public string CookieName { get; set; }
|
||||
public int ConsecutiveForbidden { get; set; }
|
||||
public DateTime? CooldownUntil { get; set; }
|
||||
public bool RequiresAuthorization { get; set; }
|
||||
public bool ProbePending { get; set; }
|
||||
public int? LastStatusCode { get; set; }
|
||||
public string LastError { get; set; }
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
public sealed class UnexcludeVideosRequest
|
||||
{
|
||||
public List<string> Ids { get; set; } = new();
|
||||
public bool CreateDownloadTask { get; set; }
|
||||
}
|
||||
|
||||
public sealed class UnexcludeVideosResult
|
||||
{
|
||||
public int ReleasedCount { get; set; }
|
||||
public int QueuedCount { get; set; }
|
||||
public string TaskId { get; set; }
|
||||
public List<string> CannotQueueIds { get; set; } = new();
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public sealed class VideoExclusionPageRequest : PageRequestDto
|
||||
{
|
||||
public string Keyword { get; set; }
|
||||
}
|
||||
|
||||
public sealed class VideoExclusionPage
|
||||
{
|
||||
public int TotalCount { get; set; }
|
||||
public List<DouyinVideoDelete> Items { get; set; } = new();
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,11 @@
|
||||
/// </summary>
|
||||
dy_followuser_once = 2000,
|
||||
|
||||
/// <summary>
|
||||
/// 独立直播状态监测任务,不属于视频下载任务。
|
||||
/// </summary>
|
||||
dy_live_monitor = 3000,
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class WebDavSettingsDto
|
||||
{
|
||||
public StorageType StorageType { get; set; }
|
||||
public string Endpoint { get; set; }
|
||||
public string BasePath { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool HasPassword { get; set; }
|
||||
public bool AllowInvalidCertificate { get; set; }
|
||||
public DateTime? LastTestedAt { get; set; }
|
||||
public string LastTestMessage { get; set; }
|
||||
}
|
||||
|
||||
public class WebDavTestRequest
|
||||
{
|
||||
public string Endpoint { get; set; }
|
||||
public string BasePath { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool AllowInvalidCertificate { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>统一的存储连接测试请求;新远端存储仅支持 OpenList。</summary>
|
||||
public class StorageTestRequest
|
||||
{
|
||||
public StorageType StorageType { get; set; }
|
||||
public string Endpoint { get; set; }
|
||||
public string BasePath { get; set; }
|
||||
public string LocalStagingPath { get; set; }
|
||||
public string SourcePath { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool AllowInvalidCertificate { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>统一的存储配置保存请求;WebDAV 字段仅为数据库升级兼容保留。</summary>
|
||||
public class StorageSettingsDto
|
||||
{
|
||||
public StorageType StorageType { get; set; }
|
||||
public string Endpoint { get; set; }
|
||||
public string BasePath { get; set; }
|
||||
public string LocalStagingPath { get; set; }
|
||||
public string SourcePath { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool AllowInvalidCertificate { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user