feat: stream-keys
This commit is contained in:
@ -72,7 +72,7 @@ public class LndInvoicesStream : BackgroundService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Subscribe invoices failed");
|
||||
//_logger.LogError(ex, "Subscribe invoices failed");
|
||||
}
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
|
||||
|
@ -22,7 +22,7 @@ public class StreamEventBuilder
|
||||
_nostrClient = nostrClient;
|
||||
}
|
||||
|
||||
public NostrEvent CreateStreamEvent(User user, UserStream stream)
|
||||
public NostrEvent CreateStreamEvent(UserStream stream)
|
||||
{
|
||||
var status = stream.State switch
|
||||
{
|
||||
@ -35,11 +35,11 @@ public class StreamEventBuilder
|
||||
var tags = new List<NostrEventTag>
|
||||
{
|
||||
new("d", stream.Id.ToString()),
|
||||
new("title", user.Title ?? ""),
|
||||
new("summary", user.Summary ?? ""),
|
||||
new("image", stream.Thumbnail ?? user.Image ?? ""),
|
||||
new("title", stream.Title ?? ""),
|
||||
new("summary", stream.Summary ?? ""),
|
||||
new("image", stream.Thumbnail ?? stream.Image ?? ""),
|
||||
new("status", status),
|
||||
new("p", user.PubKey, "", "host"),
|
||||
new("p", stream.PubKey, "wss://relay.zap.stream", "host"),
|
||||
new("relays", _config.Relays),
|
||||
new("starts", new DateTimeOffset(stream.Starts).ToUnixTimeSeconds().ToString()),
|
||||
new("service", new Uri(_config.ApiHost, "/api/nostr").ToString())
|
||||
@ -51,9 +51,9 @@ public class StreamEventBuilder
|
||||
tags.Add(new("streaming", new Uri(_config.DataHost, $"stream/{stream.Id}.m3u8").ToString()));
|
||||
tags.Add(new("current_participants", viewers.ToString()));
|
||||
|
||||
if (!string.IsNullOrEmpty(user.ContentWarning))
|
||||
if (!string.IsNullOrEmpty(stream.ContentWarning))
|
||||
{
|
||||
tags.Add(new("content-warning", user.ContentWarning));
|
||||
tags.Add(new("content-warning", stream.ContentWarning));
|
||||
}
|
||||
}
|
||||
else if (status == "ended")
|
||||
@ -70,14 +70,14 @@ public class StreamEventBuilder
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var tag in user.SplitTags())
|
||||
foreach (var tag in stream.SplitTags())
|
||||
{
|
||||
tags.Add(new("t", tag));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(user.Goal))
|
||||
if (!string.IsNullOrEmpty(stream.Goal))
|
||||
{
|
||||
tags.Add(new("goal", user.Goal));
|
||||
tags.Add(new("goal", stream.Goal));
|
||||
}
|
||||
|
||||
var ev = new NostrEvent
|
||||
|
@ -57,7 +57,7 @@ public class NostrStreamManager : IStreamManager
|
||||
TestCanStream();
|
||||
var fwds = new List<string>
|
||||
{
|
||||
$"rtmp://127.0.0.1:1935/{_context.UserStream.Endpoint.App}/{_context.User.StreamKey}?vhost={_context.UserStream.Endpoint.Forward}"
|
||||
$"rtmp://127.0.0.1:1935/{_context.UserStream.Endpoint.App}/{_context.StreamKey}?vhost={_context.UserStream.Endpoint.Forward}"
|
||||
};
|
||||
|
||||
var dataProtector = _dataProtectionProvider.CreateProtector("forward-targets");
|
||||
@ -103,7 +103,6 @@ public class NostrStreamManager : IStreamManager
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public async Task StreamStopped()
|
||||
@ -194,20 +193,27 @@ public class NostrStreamManager : IStreamManager
|
||||
{
|
||||
//var matches = new Regex("\\.(\\d+)\\.[\\w]{2,4}$").Match(segment.AbsolutePath);
|
||||
|
||||
if (_context.UserStream.Endpoint.Capabilities.Contains("dvr:source"))
|
||||
try
|
||||
{
|
||||
var result = await _dvrStore.UploadRecording(_context.UserStream, segment);
|
||||
_context.Db.Recordings.Add(new()
|
||||
if (_context.UserStream.Endpoint.Capabilities.Contains("dvr:source"))
|
||||
{
|
||||
Id = result.Id,
|
||||
UserStreamId = _context.UserStream.Id,
|
||||
Url = result.Result.ToString(),
|
||||
Duration = result.Duration,
|
||||
Timestamp = DateTime
|
||||
.UtcNow //DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(matches.Groups[1].Value)).UtcDateTime
|
||||
});
|
||||
var result = await _dvrStore.UploadRecording(_context.UserStream, segment);
|
||||
_context.Db.Recordings.Add(new()
|
||||
{
|
||||
Id = result.Id,
|
||||
UserStreamId = _context.UserStream.Id,
|
||||
Url = result.Result.ToString(),
|
||||
Duration = result.Duration,
|
||||
Timestamp = DateTime
|
||||
.UtcNow //DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(matches.Groups[1].Value)).UtcDateTime
|
||||
});
|
||||
|
||||
await _context.Db.SaveChangesAsync();
|
||||
await _context.Db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning("Failed to save recording segment {}, {}", segment, ex.Message);
|
||||
}
|
||||
|
||||
await _context.Db.Streams
|
||||
@ -242,7 +248,7 @@ public class NostrStreamManager : IStreamManager
|
||||
var existingEvent = _context.UserStream.GetEvent();
|
||||
var oldViewers = existingEvent?.Tags?.FindFirstTagValue("current_participants");
|
||||
|
||||
var newEvent = _eventBuilder.CreateStreamEvent(_context.User, _context.UserStream);
|
||||
var newEvent = _eventBuilder.CreateStreamEvent(_context.UserStream);
|
||||
var newViewers = newEvent?.Tags?.FindFirstTagValue("current_participants");
|
||||
|
||||
if (newEvent != default && int.TryParse(oldViewers, out var a) && int.TryParse(newViewers, out var b) && a != b)
|
||||
@ -260,7 +266,7 @@ public class NostrStreamManager : IStreamManager
|
||||
DateTime? ends = state == UserStreamState.Ended ? DateTime.UtcNow : null;
|
||||
_context.UserStream.State = state;
|
||||
_context.UserStream.Ends = ends;
|
||||
var ev = _eventBuilder.CreateStreamEvent(_context.User, _context.UserStream);
|
||||
var ev = _eventBuilder.CreateStreamEvent(_context.UserStream);
|
||||
|
||||
await _context.Db.Streams.Where(a => a.Id == _context.UserStream.Id)
|
||||
.ExecuteUpdateAsync(o => o.SetProperty(v => v.State, state)
|
||||
|
@ -9,4 +9,5 @@ public class StreamManagerContext
|
||||
public User User => UserStream.User;
|
||||
public StreamInfo? StreamInfo { get; init; }
|
||||
public SrsApi EdgeApi { get; init; } = null!;
|
||||
public string StreamKey { get; init; } = null!;
|
||||
}
|
||||
|
@ -28,7 +28,9 @@ public class StreamManagerFactory
|
||||
var user = await _db.Users
|
||||
.AsNoTracking()
|
||||
.Include(a => a.Forwards)
|
||||
.SingleOrDefaultAsync(a => a.StreamKey.Equals(info.StreamKey));
|
||||
.Include(user => user.StreamKeys)
|
||||
.SingleOrDefaultAsync(a =>
|
||||
a.StreamKey.Equals(info.StreamKey) || a.StreamKeys.Any(b => b.Key == info.StreamKey));
|
||||
|
||||
if (user == default) throw new Exception("No user found");
|
||||
|
||||
@ -53,24 +55,28 @@ public class StreamManagerFactory
|
||||
throw new Exception("User account blocked");
|
||||
}
|
||||
|
||||
var existingLive = await _db.Streams
|
||||
.SingleOrDefaultAsync(a => a.State == UserStreamState.Live && a.PubKey == user.PubKey);
|
||||
var singleUseKey = user.StreamKeys.FirstOrDefault(a => a.Key == info.StreamKey);
|
||||
|
||||
var existingLive = singleUseKey != default
|
||||
? await _db.Streams.SingleOrDefaultAsync(a => a.Id == singleUseKey.StreamId)
|
||||
: await _db.Streams
|
||||
.SingleOrDefaultAsync(a => a.State == UserStreamState.Live && a.PubKey == user.PubKey);
|
||||
|
||||
var stream = existingLive ?? new UserStream
|
||||
{
|
||||
EndpointId = ep.Id,
|
||||
PubKey = user.PubKey,
|
||||
StreamId = "",
|
||||
State = UserStreamState.Live,
|
||||
EdgeIp = info.EdgeIp,
|
||||
ForwardClientId = info.ClientId
|
||||
ForwardClientId = info.ClientId,
|
||||
};
|
||||
|
||||
// add new stream
|
||||
if (existingLive == default)
|
||||
{
|
||||
var ev = _eventBuilder.CreateStreamEvent(user, stream);
|
||||
stream.Event = JsonConvert.SerializeObject(ev, NostrSerializer.Settings);
|
||||
await stream.CopyLastStreamDetails(_db);
|
||||
var ev = _eventBuilder.CreateStreamEvent(stream);
|
||||
stream.Event = NostrJson.Serialize(ev) ?? "";
|
||||
_db.Streams.Add(stream);
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
@ -85,18 +91,19 @@ public class StreamManagerFactory
|
||||
var ctx = new StreamManagerContext
|
||||
{
|
||||
Db = _db,
|
||||
StreamKey = info.StreamKey,
|
||||
UserStream = new()
|
||||
{
|
||||
Id = stream.Id,
|
||||
PubKey = stream.PubKey,
|
||||
StreamId = stream.StreamId,
|
||||
State = stream.State,
|
||||
EdgeIp = stream.EdgeIp,
|
||||
ForwardClientId = stream.ForwardClientId,
|
||||
Endpoint = ep,
|
||||
User = user
|
||||
},
|
||||
EdgeApi = new SrsApi(_serviceProvider.GetRequiredService<HttpClient>(), new Uri($"http://{stream.EdgeIp}:1985"))
|
||||
EdgeApi = new SrsApi(_serviceProvider.GetRequiredService<HttpClient>(),
|
||||
new Uri($"http://{stream.EdgeIp}:1985"))
|
||||
};
|
||||
|
||||
return new NostrStreamManager(_loggerFactory.CreateLogger<NostrStreamManager>(), ctx, _serviceProvider);
|
||||
@ -108,6 +115,7 @@ public class StreamManagerFactory
|
||||
.AsNoTracking()
|
||||
.Include(a => a.User)
|
||||
.Include(a => a.Endpoint)
|
||||
.Include(a => a.StreamKey)
|
||||
.FirstOrDefaultAsync(a => a.Id == id);
|
||||
|
||||
if (stream == default) throw new Exception("No live stream");
|
||||
@ -115,8 +123,10 @@ public class StreamManagerFactory
|
||||
var ctx = new StreamManagerContext
|
||||
{
|
||||
Db = _db,
|
||||
StreamKey = stream.StreamKey?.Key ?? stream.User.StreamKey,
|
||||
UserStream = stream,
|
||||
EdgeApi = new SrsApi(_serviceProvider.GetRequiredService<HttpClient>(), new Uri($"http://{stream.EdgeIp}:1985"))
|
||||
EdgeApi = new SrsApi(_serviceProvider.GetRequiredService<HttpClient>(),
|
||||
new Uri($"http://{stream.EdgeIp}:1985"))
|
||||
};
|
||||
|
||||
return new NostrStreamManager(_loggerFactory.CreateLogger<NostrStreamManager>(), ctx, _serviceProvider);
|
||||
@ -128,6 +138,7 @@ public class StreamManagerFactory
|
||||
.AsNoTracking()
|
||||
.Include(a => a.User)
|
||||
.Include(a => a.Endpoint)
|
||||
.Include(a => a.StreamKey)
|
||||
.FirstOrDefaultAsync(a => a.PubKey.Equals(pubkey) && a.State == UserStreamState.Live);
|
||||
|
||||
if (stream == default) throw new Exception("No live stream");
|
||||
@ -135,8 +146,10 @@ public class StreamManagerFactory
|
||||
var ctx = new StreamManagerContext
|
||||
{
|
||||
Db = _db,
|
||||
StreamKey = stream.StreamKey?.Key ?? stream.User.StreamKey,
|
||||
UserStream = stream,
|
||||
EdgeApi = new SrsApi(_serviceProvider.GetRequiredService<HttpClient>(), new Uri($"http://{stream.EdgeIp}:1985"))
|
||||
EdgeApi = new SrsApi(_serviceProvider.GetRequiredService<HttpClient>(),
|
||||
new Uri($"http://{stream.EdgeIp}:1985"))
|
||||
};
|
||||
|
||||
return new NostrStreamManager(_loggerFactory.CreateLogger<NostrStreamManager>(), ctx, _serviceProvider);
|
||||
@ -148,11 +161,13 @@ public class StreamManagerFactory
|
||||
.AsNoTracking()
|
||||
.Include(a => a.User)
|
||||
.Include(a => a.Endpoint)
|
||||
.Include(a => a.StreamKey)
|
||||
.OrderByDescending(a => a.Starts)
|
||||
.FirstOrDefaultAsync(a =>
|
||||
a.User.StreamKey.Equals(info.StreamKey) &&
|
||||
a.Endpoint.App.Equals(info.App) &&
|
||||
a.State == UserStreamState.Live);
|
||||
(a.StreamKey != default && a.StreamKey.Key == info.StreamKey) ||
|
||||
(a.User.StreamKey.Equals(info.StreamKey) &&
|
||||
a.Endpoint.App.Equals(info.App) &&
|
||||
a.State == UserStreamState.Live));
|
||||
|
||||
if (stream == default)
|
||||
{
|
||||
@ -162,11 +177,13 @@ public class StreamManagerFactory
|
||||
var ctx = new StreamManagerContext
|
||||
{
|
||||
Db = _db,
|
||||
StreamKey = info.StreamKey,
|
||||
UserStream = stream,
|
||||
StreamInfo = info,
|
||||
EdgeApi = new SrsApi(_serviceProvider.GetRequiredService<HttpClient>(), new Uri($"http://{stream.EdgeIp}:1985"))
|
||||
EdgeApi = new SrsApi(_serviceProvider.GetRequiredService<HttpClient>(),
|
||||
new Uri($"http://{stream.EdgeIp}:1985"))
|
||||
};
|
||||
|
||||
return new NostrStreamManager(_loggerFactory.CreateLogger<NostrStreamManager>(), ctx, _serviceProvider);
|
||||
}
|
||||
}
|
||||
}
|
@ -254,8 +254,8 @@ public class UserService
|
||||
|
||||
public async Task UpdateStreamInfo(string pubkey, PatchEvent req)
|
||||
{
|
||||
await _db.Users
|
||||
.Where(a => a.PubKey == pubkey)
|
||||
await _db.Streams
|
||||
.Where(a => a.Id == req.Id && a.PubKey == pubkey)
|
||||
.ExecuteUpdateAsync(o => o.SetProperty(v => v.Title, req.Title)
|
||||
.SetProperty(v => v.Summary, req.Summary)
|
||||
.SetProperty(v => v.Image, req.Image)
|
||||
|
Reference in New Issue
Block a user