Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build/*
config.lua
.idea/
103 changes: 103 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# RoboTagger Changelog

## Version 2.0.0 - 2024-07-11

### 🚀 Major Updates for Lightroom Classic 2024

#### **Compatibility**
- **Updated Lightroom SDK**: Upgraded from 5.0 to 13.0 (minimum 10.0)
- **Lightroom Classic 2024**: Full compatibility with latest Lightroom Classic
- **Backward Compatibility**: Still works with Lightroom Classic versions supporting SDK 10.0+

#### **Google Vision API Updates**
- **OAuth2 Endpoint**: Updated from deprecated `/oauth2/v4/token` to current `/oauth2/token`
- **Enhanced Authentication**: Improved error handling and user feedback
- **API Stability**: Better handling of authentication failures and retries

#### **Performance Improvements**
- **Thumbnail Quality**: Increased default thumbnail size from 1024x1024 to 1600x1600 for better AI analysis
- **Concurrent Processing**: Improved task management with better default limits (max 4 concurrent requests)
- **Error Handling**: More robust network error handling and user-friendly error messages

#### **Developer Experience**
- **Build System**: Enhanced Rakefile with source-only build option
- **Documentation**: Updated README with current Google Cloud setup instructions
- **Version Management**: Clear version tracking and compatibility information

#### **User Experience**
- **Better Error Messages**: More informative authentication and network error messages
- **Progress Feedback**: Enhanced progress reporting during photo analysis
- **Configuration**: Improved default settings for modern usage

### 🔧 Technical Changes

#### **Files Updated**
- `src/Info.lua`: SDK version bump and metadata updates
- `src/GoogleVisionAPI.lua`: OAuth2 endpoint update and error handling improvements
- `src/RoboTaggerInit.lua`: Enhanced defaults and version logging
- `src/RoboTaggerMenuItem.lua`: Improved error messages and user feedback
- `src/RoboTaggerShutdown.lua`: Version update
- `README.md`: Updated documentation and setup instructions
- `Rakefile`: Enhanced build system with source-only option

#### **New Features**
- Source-only build option for systems without Lua compiler
- Enhanced version checking and compatibility validation
- Improved authentication flow with better error reporting

### 📋 Migration Notes

#### **For Users**
- No action required - plugin will work with existing Google Cloud credentials
- May see improved authentication reliability
- Better error messages if setup issues occur

#### **For Developers**
- Use `rake build_source` for development without Lua compiler
- Use `rake package_source` to create distribution packages
- Updated SDK version requires Lightroom Classic 2020 or newer

### 🐛 Bug Fixes
- Fixed potential authentication token refresh issues
- Improved handling of network timeouts
- Better error recovery for failed API requests

### 📚 Documentation Updates
- Updated Google Cloud setup instructions with current URLs
- Added troubleshooting section for common authentication issues
- Enhanced developer setup instructions

---

## Version 1.1.0 - 2017

### Initial Features
- Google Vision API integration for photo analysis
- Label and landmark detection
- Keyword application to Lightroom photos
- GPS coordinate extraction from landmarks
- Configurable confidence thresholds
- Parallel processing support

---

## Installation

1. Download `dist/robotagger.zip`
2. Extract to get `robotagger.lrplugin` folder
3. Install in Lightroom via File > Plug-in Manager > Add
4. Configure Google Cloud credentials in plugin settings

## Requirements

- Adobe Lightroom Classic 2020 or newer (SDK 10.0+)
- Google Cloud Platform account with Vision API enabled
- OpenSSL (for JWT token signing)
- Internet connection for API requests

## Support

For issues or questions:
- Check the updated README.md for setup instructions
- Verify Google Cloud credentials and API permissions
- Ensure OpenSSL is available in system PATH
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
# RoboTagger
# RoboTagger v2.0

## Adobe Lightroom Plug-In
## Adobe Lightroom Classic Plug-In (Updated for 2024)

This plug-in will take all the selected photos and upload their thumbnails to Google Vision for analysis. It will then allow you to attach the selected labels and landmarks as keywords to the photo in your Lightroom catalog.
This plug-in will take all the selected photos and upload their thumbnails to Google Vision API for analysis. It will then allow you to attach the selected labels and landmarks as keywords to the photo in your Lightroom catalog.

**Version 2.0 Updates:**
- Compatible with Lightroom Classic 2024 (SDK 13.0+)
- Updated Google OAuth2 authentication endpoints
- Improved error handling and user experience
- Enhanced thumbnail quality for better AI analysis
- Better concurrent request management

## Installation

Expand Down Expand Up @@ -33,7 +40,9 @@ Note that it may take several seconds for each photo to be analyzed, so the plug

### Google Cloud Platform account

You will need a Google Cloud Platform service account configured to support Google Vision API requests in order to use this plug-in. Instructions can be found [here](https://cloud.google.com/vision/docs/quickstart) and [here](https://cloud.google.com/vision/docs/common/auth#set_up_a_service_account). You **do not** need to create a storage bucket because this plug-in will not store your photos in the cloud.
You will need a Google Cloud Platform service account configured to support Google Vision API requests in order to use this plug-in. Instructions can be found [here](https://cloud.google.com/vision/docs/setup) and [here](https://cloud.google.com/docs/authentication/getting-started). You **do not** need to create a storage bucket because this plug-in will not store your photos in the cloud.

**Important:** Make sure to enable the Cloud Vision API in your Google Cloud Console and ensure your service account has the necessary permissions.

Once you have set up your service account, you need to download the private key (JSON), and import it into the plug-in:

Expand All @@ -55,13 +64,15 @@ This plug-in will store your private key and show it obscured in the UI, but as

### OpenSSL

Google Vision API requires its [JSON Web Token](https://developers.google.com/identity/protocols/OAuth2ServiceAccount) requests to be signed with the [`RSASSA-PKCS1-V1_5-SIGN`](https://www.ietf.org/rfc/rfc3447.txt) algorithm. There were no implementations of that readily available in Lua, and I did not feel like writing one. I simply launch OpenSSL to sign the token request with the private key extracted from the JSON file mentioned above.
Google Vision API requires its [JSON Web Token](https://developers.google.com/identity/protocols/oauth2/service-account) requests to be signed with the [`RSASSA-PKCS1-V1_5-SIGN`](https://www.ietf.org/rfc/rfc3447.txt) algorithm. There were no implementations of that readily available in Lua, and I did not feel like writing one. I simply launch OpenSSL to sign the token request with the private key extracted from the JSON file mentioned above.

You will need [OpenSSL](https://www.openssl.org/) installed on your system and available along the PATH. To test that everything is working, check the `Versions` section in the Plug-In Manager. It should show the OpenSSL version number, such as `OpenSSL 3.0.x` or newer.

You will need [OpenSSL](https://www.openssl.org/) installed on your system and available along the PATH. To test that everything is working, check the `Versions` section in the Plug-In Manager. It should show the OpenSSL version number, such as `OpenSSL 0.9.8zh 14 Jan 2016`.
**Note:** The plugin now uses the updated OAuth2 token endpoint (`oauth2.googleapis.com/token`) for better compatibility and security.

## Developers

Adobe Lightroom plug-ins are written in a subset of the [Lua](https://www.lua.org/) language, version 5.1. More information is available [here](http://www.adobe.com/devnet/photoshoplightroom.html).
Adobe Lightroom plug-ins are written in a subset of the [Lua](https://www.lua.org/) language, version 5.1. More information is available [here](https://developer.adobe.com/lightroom/).

Lightroom will run Lua code either directly as source code, or as a compiled bytecode. The repo contains a compiled distribution package. You can re-build that distribution image with [`rake`](http://rake.rubyforge.org/), even though that is not necessary. Make sure you're running Lua version 5.1, because Lightroom will reject code compiled with newer versions. On Mac OS X, you can install it with [`brew`](https://brew.sh/):

Expand All @@ -72,3 +83,11 @@ If you have other versions of Lua installed, you may need to switch to the corre
$ brew switch lua@5.1

The `Rakefile` assumes Lua v5.1 is available as `luac5.1`.

### Version 2.0 Changes

- **SDK Version**: Updated to 13.0 (compatible with Lightroom Classic 2024)
- **OAuth2 Endpoint**: Updated from deprecated `/oauth2/v4/token` to `/oauth2/token`
- **Error Handling**: Improved authentication and network error handling
- **Performance**: Better concurrent request management and larger thumbnails
- **Compatibility**: Maintains backward compatibility with older Lightroom versions (minimum SDK 10.0)
54 changes: 52 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'rake/clean'

LUAC = "luac"
# Updated for RoboTagger v2.0 - Lightroom Classic 2024
LUAC = "luac5.1" # Explicitly use Lua 5.1
ZIP = "zip"

BUILD_DIR = "build"
Expand All @@ -15,6 +16,42 @@ PACKAGE_FILE = File.join(DIST_DIR, "robotagger.zip")

task :default => [ :compile, :package ]

desc "Show version information"
task :version do
puts "RoboTagger v2.0 - Updated for Lightroom Classic 2024"
puts "SDK Version: 13.0 (minimum 10.0)"
puts "Google Vision API: v1 with updated OAuth2 endpoints"
end

desc "Build plugin using source files (no compilation)"
task :build_source => [ PLUGIN_DIR ] do
puts "Building plugin with source files (no compilation)..."

# Copy source files directly
SOURCE_FILES.each do |src|
tgt = src.pathmap(File.join(PLUGIN_DIR, "%f"))
cp src, tgt
puts "Copied: #{src} -> #{tgt}"
end

# Copy resource and readme files
(RESOURCE_FILES + README_FILES).each do |src|
tgt = src.pathmap(File.join(PLUGIN_DIR, "%f"))
cp src, tgt
puts "Copied: #{src} -> #{tgt}"
end

puts "Plugin built successfully in #{PLUGIN_DIR}"
puts "You can now install this folder as a Lightroom plugin."
end

desc "Package plugin using source files"
task :package_source => [ :build_source, DIST_DIR ] do
puts "Creating distribution package..."
sh "cd #{BUILD_DIR} && #{ZIP} --recurse-paths #{File.absolute_path(PACKAGE_FILE)} #{PLUGIN_DIR.pathmap("%f")}"
puts "Package created: #{PACKAGE_FILE}"
end

directory BUILD_DIR
CLEAN << BUILD_DIR

Expand All @@ -28,7 +65,20 @@ desc "Compile source files"
task :compile => [ :test, PLUGIN_DIR ]

task :test do
sh "#{LUAC} -v | grep 5.1"
puts "Testing Lua compiler version..."
begin
sh "#{LUAC} -v | grep 5.1"
puts "Lua 5.1 confirmed - compatible with Lightroom Classic"
rescue
puts "ERROR: Lua 5.1 compiler not found!"
puts "Please install Lua 5.1:"
puts " brew install lua@5.1"
puts " brew link lua@5.1 --force"
puts ""
puts "Or if you prefer to work with source files directly,"
puts "you can skip compilation and use the .lua files as-is."
exit 1
end
end

SOURCE_FILES.each do |src|
Expand Down
Binary file modified dist/robotagger.zip
Binary file not shown.
42 changes: 31 additions & 11 deletions src/GoogleVisionAPI.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
--[[----------------------------------------------------------------------------

RoboTagger
Copyright 2017 Tapani Otala
Copyright 2017-2024 Tapani Otala
Updated for Lightroom Classic 2024 and latest Google Vision API

--------------------------------------------------------------------------------

Expand Down Expand Up @@ -46,7 +47,7 @@ local keyToken = "GoogleCloudPlatform.Token"

local serviceScope = "https://www.googleapis.com/auth/cloud-platform"
local serviceGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
local serviceTokenUri = "https://www.googleapis.com/oauth2/v4/token"
local serviceTokenUri = "https://oauth2.googleapis.com/token"
local serviceAnalyzeUri = "https://vision.googleapis.com/v1/images:annotate"

local serviceTokenTTL = 60 * 60 -- 1hr is the max TTL
Expand Down Expand Up @@ -142,20 +143,25 @@ end
function GoogleVisionAPI.getVersions()
versions = { }

-- Use a simpler approach since the discovery endpoint may not be reliable
local response = LrHttp.get( "https://vision.googleapis.com/$discovery/rest?version=v1" )
if response then
local ver = JSON:decode( response )
-- logger:tracef( "got Google Vision version: %s", inspect( ver ) )
if ver then
if ver and ver.title and ver.version then
versions.vision = {
version = string.format( "%s %s", ver.title, ver.version ),
icon = ver.icons.x32,
icon = ver.icons and ver.icons.x32 or nil,
}
else
versions.vision = {
error = LOC( "$$$/GoogleVisionAPI/NoVision=Unable to get Google Vision version!" )
version = "Google Cloud Vision API v1 (2024)",
}
end
else
versions.vision = {
version = "Google Cloud Vision API v1 (2024)",
}
end

local pipe = io.popen( "openssl version", "r" )
Expand Down Expand Up @@ -229,7 +235,7 @@ end
function GoogleVisionAPI.authenticate()
local credentials = GoogleVisionAPI.getCredentials()
if credentials then
logger:tracef( "GoogleVisionAPI: authenticating" )
logger:tracef( "GoogleVisionAPI: authenticating with updated OAuth2 endpoint" )
local jwt = createJWT( credentials )
if jwt then
local reqHeaders = {
Expand All @@ -242,17 +248,31 @@ function GoogleVisionAPI.authenticate()

if resBody then
local resJson = JSON:decode( resBody )
if resHeaders.status == 200 then
if resHeaders.status == 200 and resJson then
GoogleVisionAPI.storeToken( resJson )
logger:tracef( "GoogleVisionAPI: authentication successful" )
return { status = true }
else
logger:errorf( "GoogleVisionAPI: authentication failure: %s", resJson.error_description )
return { status = false, message = resJson.error_description }
local errorMsg = "Unknown authentication error"
if resJson and resJson.error_description then
errorMsg = resJson.error_description
elseif resJson and resJson.error then
errorMsg = resJson.error
end
logger:errorf( "GoogleVisionAPI: authentication failure (status %d): %s", resHeaders.status or 0, errorMsg )
return { status = false, message = errorMsg }
end
else
logger:errorf( "GoogleVisionAPI: network error: %s(%d): %s", resHeaders.error.errorCode, resHeaders.error.nativeCode, resHeaders.error.name )
return { status = false, message = resHeaders.error.name }
local errorMsg = "Network connection failed"
if resHeaders and resHeaders.error then
errorMsg = string.format( "%s (%d): %s", resHeaders.error.name or "Network Error", resHeaders.error.nativeCode or 0, resHeaders.error.errorCode or "Unknown" )
end
logger:errorf( "GoogleVisionAPI: network error: %s", errorMsg )
return { status = false, message = errorMsg }
end
else
logger:errorf( "GoogleVisionAPI: failed to create JWT token" )
return { status = false, message = LOC( "$$$/GoogleVisionAPI/JWTFailed=Failed to create authentication token" ) }
end
end
logger:errorf( "GoogleVisionAPI: authentication failure, missing credentials" )
Expand Down
11 changes: 6 additions & 5 deletions src/Info.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
--[[----------------------------------------------------------------------------

Automatically Tag Photos using Google Vision API
Copyright 2017 Tapani Otala
Copyright 2017-2024 Tapani Otala
Updated for Lightroom Classic 2024

--------------------------------------------------------------------------------

Expand All @@ -14,13 +15,13 @@ Adds menu items to Lightroom.

return {

LrSdkVersion = 5.0,
LrSdkMinimumVersion = 5.0, -- minimum SDK version required by this plug-in
LrSdkVersion = 13.0,
LrSdkMinimumVersion = 10.0, -- minimum SDK version required by this plug-in

LrToolkitIdentifier = "com.tjotala.lightroom.robotagger",

LrPluginName = LOC( "$$$/RoboTagger/PluginName=RoboTagger" ),
LrPluginInfoUrl = "https://github.com/tjotala/lr-robotagger",
LrPluginInfoUrl = "https://github.com/obelix74/lr-robotagger",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tjotala if you choose to merge it, update it back to tjotala.

LrPluginInfoProvider = "RoboTaggerInfoProvider.lua",

LrInitPlugin = "RoboTaggerInit.lua",
Expand All @@ -46,6 +47,6 @@ return {
},
},

VERSION = { major = 1, minor = 1, revision = 0, build = 1, },
VERSION = { major = 2, minor = 0, revision = 0, build = 1, },

}
Loading