BLAM3.SDK 3.1.7.25

dotnet add package BLAM3.SDK --version 3.1.7.25                
NuGet\Install-Package BLAM3.SDK -Version 3.1.7.25                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BLAM3.SDK" Version="3.1.7.25" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add BLAM3.SDK --version 3.1.7.25                
#r "nuget: BLAM3.SDK, 3.1.7.25"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install BLAM3.SDK as a Cake Addin
#addin nuget:?package=BLAM3.SDK&version=3.1.7.25

// Install BLAM3.SDK as a Cake Tool
#tool nuget:?package=BLAM3.SDK&version=3.1.7.25                

Blue Lucy SDK

Blue Lucy is a media services integration platform that unifies production and supply chain operations for the media industry. The Blue Lucy .Net SDK provides the coding framework for developers to create their own BLidgets and Plugins for running within the Blue Lucy Workflow Runner. It can also be used to rapidly delevop bespoke integrations directly with the Blue Lucy API.

Blue Lucy SDK Logo

NuGet Packages

Package Latest Version
BLAM3.SDK NuGet

Documentation

This README provides a quick overview of how to make use of the Blue Lucy .Net SDK. You can check out some sample code on our public GitHub repository for more in depth examples.

Quick Start

[!IMPORTANT] To use the Blue Lucy .Net SDK, you will need to have an active application account on a Blue Lucy system. Please contact support, or your system adminstrator for assistance in setting up an account on your system.

To get started, first add the BLAM3.SDK package to your project by running the following command:

dotnet add package BLAM3.SDK

You can now create a BlamClient using your application credentials and begin searching your media:

// Create a new BlamClient instance using application credentials
var blamClient = new BlamClient(new BlamClientConfig
{
    BlamApiEndpoint = "https://<your>.bluelucy.com/api",
    Username = "<ApplicationUsername>",
    Password = "<ApplicationPassword>"
});

// Search for the first 100 video assets
var results = await blamClient.Search(new SearchQueryInputModel
{
    Query = "type=video",
    Limit = 100
});

// Select first asset from search results
var asset = results.Items.First();

Update asset metadata

// Create a new metadata snapshot updating just the specified values
var snapshot = await blamClient.CreateMetadataSnapshot(new AssetMetadataSnapshotInputModel
{
    AssetId = asset.Id,
    Values = new Dictionary<string, object>
    {
        { "show_name", "Cats on Air" },
        { "vtr", 899223 },
        { "language", "Dutch" },
        { "tx_date", "2033-01-01T15:00:00+01:00" },
        { "for_broadcast", true }
    },
    Merge = true
});

Updating the metadata on an asset creates a new snapshot version. Creating a snapshot with Merge = true will use the current metadata as the snapshot base and replace just the specified values.

Add an asset to a folder

// Search for an existing folder
var folders = await blamClient.Search(new FolderQueryInputModel
{
    Query = "name=Cats on Air",
    Limit = 1,
    Depth = FolderStructureDepth.Contents
});

// Select first folder from search results
var folder = folders.Items.First();

// Attach the asset to the folder
await blamClient.AttachAssetsToFolder(new FolderAssetListInputModel
{
    FolderId = folder.Id,
    AssetIds = [asset.Id]
});

Assets can be added or removed in bulk by providing a collection of asset Ids.

// Create a temporary link to the proxy file
var link = await blamClient.CreateStreamToken(new StreamTokenRequestInputModel
{
    Asset = new AssetSelectorInputModel { AssetId = asset.Id, Selector = "Current Version;Browse" },
    MaxAllowedClaims = MaxAllowedClaims.Unlimited,
    ShortUrl = true
});

// Use the url for streaming
var url = link.Url;

Links can be single or multi-use and a sharable with external users or processes (e.g. transcoding into different formats).

Triggering a workflow

// Fetch the list of available workflows
var blueprints = await blamClient.GetWorkflowBlueprints();
var blueprint = blueprints.First(b => b.Name == "Deliver Asset to S3");

// Trigger the selected workflow blueprint
var run = await blamClient.TriggerWorkflow(blueprint.Id, new WorkflowRunInputModel
{
    Name = "Delivery for <Customer>",
    Type = BlidgetDataType.Assets,
    Data = new AssetsIO { AssetIds = [asset.Id] }
});

// Check the current state of the workflow run
var runState = await blamClient.GetWorkflowRun(run.Ids.First());
while (runState.Status != WorkflowRunStatus.Complete)
{
    // ...
}

[!IMPORTANT] Workflows can be highly customised per platform. You should contact your workflow administrator to understand what workflows you have access to on your platform. Access to some workflows can be restricted based on your account group access permissions.

BLidgets

BLidgets are short lived micro-processes executed as steps within a Blue Lucy workflow. A BLidget represents a "unit of work" within a workflow and its scope limited to a single task during execution (e.g. Transcode video, Copy file, Import metadata, Run job etc.)

The Blue Lucy SDK simplifies BLidget creation by providing an inheritable base class which implements the BLidget control flow and handles the passing of messages between the BLidget process and the Workflow runner.

BLidget control flow is broken down into 3 phases; Init, Run and Complete:

// ExampleBlidget implements base class `Blidget` with I/O of type `AssetsIO`
internal class ExampleBlidget : Blidget<AssetsIO, AssetsIO>
{
    private BlamClient _client;
    private ExampleState _runState;

    // INIT PHASE - runs on every blidget run
    protected override void Init(AssetsIO inputData)
    {
        _client = new BlamClient();                 // Initialise BlamClient (inherits configuration from the Workflow runner)
        _runState = GetRunState<ExampleState>();    // Initialise or retrieve the current saved run state
    }
    
    // INIT PAHSE - runs on every blidget run (asynchronous variant of `void Init(...)`)
    // protected override Task InitAsync(AssetsIO inputData)
    // {
    //     // Asynchronous init operations
    // }

    // RUN PHASE - runs on the first BLidget execution only, skipped after waking up from `Waiting` or `Idle`
    protected override async Task<BlidgetOutput<AssetsIO>> RunAsync(AssetsIO inputData)
    {
        // Fetch BLidget configuration value
        var nameTemplate = GetArgument<string>("name_template");

        foreach (var assetId in inputData.AssetIds)
        {
            // Fetch input resources
            var asset = await _client.GetAssetById(assetId);

            // Use interpolator to resolve runtime values
            var name = await Interpolate(nameTemplate, _client, new TemplateData { Asset = asset });

            // Do work ...

            // Add data to the run state
            var job = new Job { Uuid = Guid.NewGuid() };
            _runState.Jobs.Add(job);
                
            // Log Debug message
            LogDebug("Added job with ID: '{id}'", job.Uuid);
        }

        // End process and save current run state; wake again once time has elapsed or receiving a call back
        return Waiting(_runState, pollingIntervalSeconds: PollingInterval.OneHour, message: "Waking again in one hour.");

        // or return Idle(_runState, _runState.Jobs.Select(j => new Callback("jobId", $"{j.Uuid}")), message: "Waking on callback.");
        // or return Complete(inputData);
    }

    // COMPLETE PHASE - called each time the BLidget runs after waking up from `Waiting` or `Idle`
    protected override async Task<BlidgetOutput<AssetsIO>> CompleteAsync(AssetsIO inputData)
    {
        // Loop through jobs and update run state
        foreach (var job in _runState.Jobs)
        {
            // Do work ...

            // Update progress state (used to report progress)
            UpdateProgress(50, "Processed 1 of 2 job(s).");
        }

        // Complete process and pass on output data
        return Complete(inputData, message: $"Processed {_runState.Jobs.Count} job(s).");

        // or return Waiting(_runState, pollingIntervalSeconds: PollingInterval.OneHour, message: "Waking again in one hour.");
        // or return Idle(_runState, _runState.Jobs.Select(j => new Callback("jobId", $"{j.Uuid}")), message: "Waking on callback.");
    }
}

internal class ExampleState
{
    public List<Job> Jobs { get; set; } = [];
}

internal class Job
{
    public Guid Uuid { get; set; }
}

More detailed examples can be found on the samples GitHub repository.

Plugins

Plugins are long running processes which are commonly used for watching for and reacting to internal or external events (e.g. files moving into a folder, a timer elapsing, receiving a message). They can also be used as extensions to the API by implementing additional end points or even act as web server for custom UIs.

Plugins implement the .Net IHostedService and provide two methods for control flow; OnStart and OnStop. Additional services or middleware can also be added using .Net's Dependency Injection allowing developers to create fully featured services within a single Plugin.

There are two possible builder patterns depending on whether a web server is required:

Service Pattern

// ExamplePlugin implements base class `PluginInitialiser`
internal class ExamplePlugin : PluginInitialiser
{
    private async Task CreateHostedService()
    {
        var builder = new HostBuilder()
            .ConfigureAppConfiguration((hostContext, configuration) =>
            {

            })
            .ConfigureServices((hostContext, services) =>
            {   // Configure serivces using dependency injection
                services.AddSingleton<BlamClient>();
                services.AddHostedService<ExamplePluginService>();
            });

        var host = builder
            .Build();

        // Runs hosted service(s)
        await host.RunAsync();
    }

    public override async Task InitAsync()
    {   // Plugin entry point - fetch configuration values here by calling `GetArgumnet`
        await CreateHostedService();
    }
}

// Inject `BlamClient` singleton using dependency injection
internal class ExamplePluginService(BlamClient client) : PluginService
{
    private ExampleState _runState;
    private WorkflowBlueprintViewModel _blueprint;

    // ONSTART PHASE - called when the hosted service first starts on `host.RunAsync()`
    protected override async Task OnStartAsync(CancellationToken cancellationToken)
    {
        _runState = GetRunState<ExampleState>();                        // Initialise or retrieve the current saved run state

        var blueprintId = GetArgument<int>("blueprint_id");             // Fetch BLidget configuration value
        _blueprint = await client.GetWorkflowBlueprint(blueprintId);    // Fetch argument resource

        ProcessWork(cancellationToken);                                 // Begin work
    }

    // ONSTOP PHASE - called when the host application is stopped e.g. SIGTERM received
    protected override Task OnStopAsync(CancellationToken cancellationToken)
    {
        // Clean up steps ...

        return Task.CompletedTask;
    }

    private void ProcessWork(CancellationToken cancellationToken) =>
        Task.Run(async () => await ProcessWorkAsync(cancellationToken), cancellationToken);

    private async Task ProcessWorkAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            // Do work ...

            // Save run state during plugin execution
            Save(_runState);

            // Log Debug
            LogDebug("Saved run state.");
        }
    }
}

internal class ExampleState
{
    public List<TrackedItem> Items { get; set; }
}

internal class TrackedItem
{
    public Guid Uuid { get; set; }
}

Web Server Pattern

// ExamplePlugin implements base class `PluginInitialiser`
internal class ExamplePlugin : PluginInitialiser
{
    private async Task CreateWebApp(string baseRoute, int port)
    {
        baseRoute = string.IsNullOrWhiteSpace(baseRoute) ? null : $"/{baseRoute}";

        var builder = WebApplication.CreateBuilder();

        // Configure serivces using dependency injection
        builder.Services.AddSingleton<ExamplePluginService>();
        builder.Services.AddHostedService(p => p.GetService<ExamplePluginService>());
        builder.Logging.ClearProviders();

        var app = builder.Build();

        // Define API endpoints using .Net minimal API
        app.MapGet($"{baseRoute}/hello", () =>
        {
            return "hello, world";
        });

        // Start web server and listen on incoming port
        await app.RunAsync($"http://*:{port}");
    }

    public override async Task InitAsync()
    {   // Plugin entry point - fetch configuration values here by calling `GetArgumnet`
        var baseRoute = GetArgument<string>("base_route");
        var port = GetArgument<int>("port");
        await CreateWebApp(baseRoute.Trim('/'), port);
    }
}

Next steps

To learn more about Blue Lucy, visit the Blue Lucy website.

Samples

  • Samples: Samples in this repository serve as a reference for developing BLigdets and Plugins
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.1.7.25 215 12/4/2024
3.1.5.12 2,087 5/16/2024
3.1.5.11 289 5/7/2024
3.1.5.8 470 4/3/2024
3.1.4.9 510 2/6/2024
3.1.4.8 126 2/5/2024
3.1.3.19 179 2/5/2024
3.1.3.16 1,744 10/4/2023
3.1.0.25 329 8/14/2023
3.1.0.24 332 7/25/2023
3.1.0.23 208 7/17/2023
3.1.0.19 431 6/20/2023
3.1.0.18 215 6/8/2023
3.0.8.16 337 3/15/2023
3.0.8.11 356 2/7/2023
3.0.8.10 362 2/1/2023
3.0.7.16 461 11/29/2022
3.0.7.13 1,073 11/9/2022
3.0.6.62 482 10/4/2022
3.0.6.60 790 7/25/2022
3.0.6.59 501 7/15/2022
3.0.6.57 580 7/7/2022
3.0.6.49 586 6/15/2022
3.0.6.44 1,981 5/18/2022
3.0.6.42 546 5/11/2022
3.0.6.34 741 4/19/2022
3.0.6.33 594 4/7/2022
3.0.6.23 573 3/15/2022
3.0.6.21 545 3/7/2022
3.0.6.20 532 2/28/2022
3.0.6.14 564 1/16/2022
3.0.6.10 1,820 12/23/2021
3.0.6.8 385 12/15/2021
3.0.6.6 386 12/10/2021
3.0.6.5 552 12/9/2021
3.0.6.4 384 12/2/2021
3.0.6.2 3,078 11/25/2021
3.0.6 421 11/17/2021
3.0.5.46 430 11/10/2021
3.0.5.45 417 11/8/2021
3.0.5.42 410 10/26/2021
3.0.5.41 448 10/19/2021
3.0.5.36 496 9/15/2021
3.0.5.35 482 9/9/2021
3.0.5.34 462 8/31/2021
3.0.5.33 449 8/26/2021
3.0.5.32 423 8/20/2021
3.0.5.31 427 8/20/2021
3.0.5.30 442 8/19/2021
3.0.5.29 437 8/18/2021
3.0.5.28 433 8/18/2021
3.0.5.27 425 8/18/2021
3.0.5.26 439 8/16/2021
3.0.5.25 425 8/13/2021
3.0.5.24 441 8/12/2021
3.0.5.23 577 7/23/2021
3.0.5.22 410 7/21/2021
3.0.5.21 474 7/16/2021
3.0.5.20 482 7/16/2021
3.0.5.19 473 7/6/2021
3.0.5.18 551 6/24/2021
3.0.5.17 554 6/12/2021
3.0.5.16 490 6/3/2021
3.0.5.15 484 6/1/2021
3.0.5.14 470 5/20/2021
3.0.5.13 462 5/13/2021
3.0.5.12 446 5/10/2021
3.0.5.10 484 4/27/2021
3.0.5.8 484 4/21/2021
3.0.5.7 460 4/20/2021
3.0.5.5 486 4/9/2021
3.0.5.4 473 4/8/2021
3.0.5.3 431 4/1/2021
3.0.5.2 444 3/31/2021
3.0.5.1 446 3/31/2021
3.0.5 481 3/26/2021
3.0.4.14 505 3/24/2021
3.0.4.13 478 3/10/2021
3.0.4.12 472 3/8/2021
3.0.4.11 467 3/5/2021
3.0.4.10 449 3/4/2021
3.0.4.9 465 3/3/2021
3.0.4.8 490 3/2/2021
3.0.4.7 528 2/26/2021
3.0.4.6 513 2/24/2021
3.0.4.5 513 2/17/2021
3.0.4.4 509 2/11/2021
3.0.4.3 503 2/11/2021
3.0.4.2 504 2/9/2021
3.0.4.1 483 2/3/2021
3.0.4 511 2/2/2021
3.0.3.9 556 1/26/2021
3.0.3.8 500 1/26/2021
3.0.3.7 510 1/20/2021
3.0.3.6 502 1/18/2021
3.0.3.5 558 1/14/2021
3.0.3.4 521 1/12/2021
3.0.3.3 497 1/11/2021
3.0.3.2 498 1/10/2021
3.0.3 525 1/5/2021
3.0.2.9 529 12/23/2020
3.0.2.8 532 12/22/2020
3.0.2.7 574 12/10/2020
3.0.2.6 559 12/9/2020
3.0.2.5 537 12/8/2020
3.0.2.4 595 11/20/2020
3.0.2.3 554 11/19/2020
3.0.2.2 566 11/19/2020
3.0.2.1 583 11/18/2020
3.0.2 577 11/17/2020
3.0.1.49 569 11/11/2020
3.0.1.48 552 11/9/2020
3.0.1.47 564 10/27/2020
3.0.1.46 725 10/13/2020
3.0.1.45 577 10/12/2020
3.0.1.44 549 10/12/2020
3.0.1.43 584 10/8/2020
3.0.1.42 543 10/6/2020
3.0.1.41 559 10/5/2020
3.0.1.40 555 10/2/2020
3.0.1.39 537 10/1/2020
3.0.1.38 574 9/30/2020
3.0.1.37 555 9/30/2020
3.0.1.35 615 9/28/2020
3.0.1.34 598 9/11/2020
3.0.1.33 623 9/3/2020
3.0.1.32 585 9/1/2020
3.0.1.31 577 8/26/2020
3.0.1.30 582 8/25/2020
3.0.1.29 586 8/21/2020
3.0.1.28 564 8/18/2020
3.0.1.27 576 8/18/2020
3.0.1.26 560 8/17/2020
3.0.1.25 543 8/14/2020
3.0.1.24 553 8/10/2020
3.0.1.23 624 8/6/2020
3.0.1.22 659 7/29/2020
3.0.1.21 630 7/29/2020
3.0.1.20 583 7/29/2020
3.0.1.19 672 7/16/2020
3.0.1.18 593 7/15/2020
3.0.1.17 601 7/13/2020
3.0.1.16 657 7/10/2020
3.0.1.15 560 7/10/2020
3.0.1.14 625 7/8/2020
3.0.1.13 564 7/7/2020
3.0.1.12 663 7/2/2020
3.0.1.11 565 7/2/2020
3.0.1.10 584 7/2/2020
3.0.1.9 544 7/1/2020
3.0.1.8 539 7/1/2020
3.0.1.7 593 6/30/2020
3.0.1.6 571 6/30/2020
3.0.1.5 576 6/23/2020
3.0.1.4 634 6/22/2020
3.0.1.3 644 6/15/2020
3.0.1.2 680 6/14/2020
3.0.0.1 657 6/12/2020
3.0.0 649 6/10/2020
0.4.34 583 6/5/2020
0.4.33 683 6/4/2020
0.4.32 631 6/3/2020
0.4.31 629 6/2/2020
0.4.30 689 5/29/2020
0.4.29 617 5/20/2020
0.4.28 607 5/19/2020
0.4.27 634 5/5/2020
0.4.26 694 5/3/2020
0.4.25 630 5/1/2020
0.4.24 621 4/27/2020
0.4.23 629 4/23/2020
0.4.22 583 4/20/2020
0.4.21 577 4/20/2020
0.4.20 628 4/13/2020
0.4.19 764 4/3/2020
0.4.18 634 3/30/2020
0.4.16 757 3/28/2020
0.4.15 636 3/26/2020
0.4.14 701 3/25/2020
0.4.13 615 3/20/2020
0.4.12 597 3/19/2020
0.4.11 631 3/17/2020
0.4.10 624 3/10/2020
0.4.8 602 3/6/2020
0.4.7 593 3/6/2020
0.4.6 596 3/6/2020
0.4.5 639 3/5/2020
0.4.4 649 3/4/2020
0.4.3 626 2/27/2020
0.4.2 576 2/26/2020
0.4.1 631 2/18/2020
0.4.0 746 2/17/2020
0.0.3.24 658 2/17/2020
0.0.3.23 597 2/13/2020
0.0.3.22 648 2/10/2020
0.0.3.21 732 2/8/2020
0.0.3.20 746 1/30/2020
0.0.3.18 647 1/27/2020
0.0.3.17 667 1/17/2020
0.0.3.16 617 1/17/2020
0.0.3.15 604 1/17/2020
0.0.3.14 756 1/9/2020
0.0.3.13 677 1/8/2020
0.0.3.12 673 1/7/2020
0.0.3.11 657 1/6/2020
0.0.3.10 741 1/3/2020
0.0.3.9 716 1/2/2020
0.0.3.8 730 12/31/2019
0.0.3.7 681 12/20/2019
0.0.3.6 870 12/18/2019
0.0.3.5 673 12/17/2019
0.0.3.4 711 12/16/2019
0.0.3.3 732 12/2/2019
0.0.3.2 644 11/20/2019
0.0.3.1 694 11/18/2019
0.0.3 663 11/7/2019
0.0.2.9 693 11/1/2019
0.0.2.8 674 10/30/2019
0.0.2.7 785 10/26/2019
0.0.2.6 792 10/24/2019
0.0.2.5 673 10/22/2019
0.0.2.4 1,440 10/11/2019
0.0.2.3 676 10/11/2019
0.0.2.2 699 10/1/2019
0.0.2.1 687 9/26/2019
0.0.2 712 9/26/2019