├── .gitignore
├── screenshots
├── remove.png
├── export-1.png
├── manual-add-1.png
├── manual-add-2.png
└── manual-add-3.png
├── dayone.lrdevplugin
├── Info.lua
├── ServiceProvider.lua
├── uuid4.lua
├── ExportDialogSections.lua
└── ExportTask.lua
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | Lightroom\ SDK\ 3.0/*
3 | test/
4 |
--------------------------------------------------------------------------------
/screenshots/remove.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philipbl/Day-One-Lightroom-Plugin/HEAD/screenshots/remove.png
--------------------------------------------------------------------------------
/screenshots/export-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philipbl/Day-One-Lightroom-Plugin/HEAD/screenshots/export-1.png
--------------------------------------------------------------------------------
/screenshots/manual-add-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philipbl/Day-One-Lightroom-Plugin/HEAD/screenshots/manual-add-1.png
--------------------------------------------------------------------------------
/screenshots/manual-add-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philipbl/Day-One-Lightroom-Plugin/HEAD/screenshots/manual-add-2.png
--------------------------------------------------------------------------------
/screenshots/manual-add-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philipbl/Day-One-Lightroom-Plugin/HEAD/screenshots/manual-add-3.png
--------------------------------------------------------------------------------
/dayone.lrdevplugin/Info.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (c) 2013, Philip Lundrigan
2 | -- All rights reserved.
3 | -- BSD License
4 |
5 | return {
6 |
7 | LrSdkVersion = 3.0,
8 | LrToolkitIdentifier = 'com.philiplundrigan.dayone_export',
9 |
10 | LrPluginName = LOC "$$$/DayOneExport/PluginName=Day One Exporter",
11 | LrPluginInfoUrl = 'https://github.com/philipbl/Day-One-Lightroom-Plugin',
12 |
13 | LrExportServiceProvider = {
14 | title = "Day One",
15 | file = 'ServiceProvider.lua',
16 | },
17 |
18 | VERSION = { major=1, minor=2, revision=1},
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/dayone.lrdevplugin/ServiceProvider.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (c) 2013, Philip Lundrigan
2 | -- All rights reserved.
3 | -- BSD License
4 |
5 | require "ExportDialogSections"
6 | require "ExportTask"
7 |
8 | local LrPathUtils = import 'LrPathUtils'
9 |
10 | return {
11 | hideSections = { 'exportLocation', 'fileNaming' },
12 | allowFileFormats = { 'JPEG' },
13 |
14 | exportPresetFields = {
15 | { key = 'use_time', default = true },
16 | { key = 'use_location', default = true },
17 | { key = 'star', default = false },
18 | { key = 'use_keywords', default = false },
19 | { key = 'use_specific_tags', default = false },
20 | { key = 'tags', default = "" },
21 | { key = 'use_activity', default = false },
22 | { key = 'activity', default = "" },
23 | { key = 'journal_type', default = 'Dropbox' },
24 | { key = 'custom', default = false },
25 | { key = 'custom_path', default = '' },
26 | { key = 'path', default = dropboxPath },
27 | },
28 |
29 | sectionsForTopOfDialog = ExportDialogSections.sectionsForTopOfDialog,
30 |
31 | processRenderedPhotos = ExportTask.processRenderedPhotos,
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, Philip Lundrigan
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the name of this program nor the
12 | names of its contributors may be used to endorse or promote products
13 | derived from this software without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL PHILIP LUNDRIGAN BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/dayone.lrdevplugin/uuid4.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | The MIT License (MIT)
3 | Copyright (c) 2012 Toby Jennings
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6 | associated documentation files (the "Software"), to deal in the Software without restriction,
7 | including without limitation the rights to use, copy, modify, merge, publish, distribute,
8 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all copies or substantial
12 | portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 | --]]
20 |
21 | local M = {}
22 | -----
23 | math.randomseed( os.time() )
24 | math.random()
25 | -----
26 | local function num2bs(num)
27 | local _mod = math.fmod or math.mod
28 | local _floor = math.floor
29 | --
30 | local result = ""
31 | if(num == 0) then return "0" end
32 | while(num > 0) do
33 | result = _mod(num,2) .. result
34 | num = _floor(num*0.5)
35 | end
36 | return result
37 | end
38 | --
39 | local function bs2num(num)
40 | local _sub = string.sub
41 | local index, result = 0, 0
42 | if(num == "0") then return 0; end
43 | for p=#num,1,-1 do
44 | local this_val = _sub( num, p,p )
45 | if this_val == "1" then
46 | result = result + ( 2^index )
47 | end
48 | index=index+1
49 | end
50 | return result
51 | end
52 | --
53 | local function padbits(num,bits)
54 | if #num == bits then return num end
55 | if #num > bits then print("too many bits") end
56 | local pad = bits - #num
57 | for i=1,pad do
58 | num = "0" .. num
59 | end
60 | return num
61 | end
62 | --
63 | local function getUUID()
64 | local _rnd = math.random
65 | local _fmt = string.format
66 | --
67 | _rnd()
68 | --
69 | local time_low_a = _rnd(0, 65535)
70 | local time_low_b = _rnd(0, 65535)
71 | --
72 | local time_mid = _rnd(0, 65535)
73 | --
74 | local time_hi = _rnd(0, 4095 )
75 | time_hi = padbits( num2bs(time_hi), 12 )
76 | local time_hi_and_version = bs2num( "0100" .. time_hi )
77 | --
78 | local clock_seq_hi_res = _rnd(0,63)
79 | clock_seq_hi_res = padbits( num2bs(clock_seq_hi_res), 6 )
80 | clock_seq_hi_res = "10" .. clock_seq_hi_res
81 | --
82 | local clock_seq_low = _rnd(0,255)
83 | clock_seq_low = padbits( num2bs(clock_seq_low), 8 )
84 | --
85 | local clock_seq = bs2num(clock_seq_hi_res .. clock_seq_low)
86 | --
87 | local node = {}
88 | for i=1,6 do
89 | node[i] = _rnd(0,255)
90 | end
91 | --
92 | local guid = ""
93 | guid = guid .. padbits(_fmt("%X",time_low_a), 4)
94 | guid = guid .. padbits(_fmt("%X",time_low_b), 4) .. "-"
95 | guid = guid .. padbits(_fmt("%X",time_mid), 4) .. "-"
96 | guid = guid .. padbits(_fmt("%X",time_hi_and_version), 4) .. "-"
97 | guid = guid .. padbits(_fmt("%X",clock_seq), 4) .. "-"
98 | --
99 | for i=1,6 do
100 | guid = guid .. padbits(_fmt("%X",node[i]), 2)
101 | end
102 | --
103 | return guid
104 | end
105 | --
106 | M.getUUID = getUUID
107 | return M
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Day One Lightroom Plug-in
2 |
3 | This plug-in creates an export service for Lightroom that allows you to export pictures directly to Day One or Day One 2.
4 |
5 | **Disclaimer**: The software is supplied "as is" and all use is at your own risk. Make sure to back up your journal entries!
6 |
7 | ## Day One 2
8 |
9 | The plug-in has been updated to support [Day One 2](http://dayoneapp.com/2016/01/introducing-day-one-2/). To export pictures to Day One 2, select it as your "Journal Location". There is currently no supported way of adding multiple pictures to an entry except through the apps. When this changes, I will update the plug-in to support multiple photos in one entry.
10 |
11 | ## Install
12 |
13 | First, [download][1] the project and unzip it. Next, rename `dayone.lrdevplugin` to `dayone.lrplugin`. The `.lrdevplugin` is used for when a plug-in is being developed.
14 |
15 | There are two ways to add the plug-in to Lightroom. You can either put the plug-in anywhere on your hard drive and add it manually to Lightroom, or you can put it into Lightroom's plug-in directory and it will recognize it automatically.
16 |
17 |
18 | ### Manually
19 | To add the plug-in manually, first choose a location where you want to place the plug-in and move it there. Next, inside Lightroom, select `File > Plug-in Manager...`.
20 |
21 | 
22 |
23 | Press `Add` on the bottom left of the dialog box and locate the plug-in. When you add the plug-in, it should be automatically enabled.
24 |
25 | 
26 |
27 | 
28 |
29 |
30 | ### Automatically
31 | To add the plug-in automatically, move the plug-in to the modules folder of Lightroom. The location of the modules folder is dependent on the operating system you are using.
32 |
33 | Operating System | Path
34 | -----------------|------
35 | In Mac OS (current user) | `~/Library/Application Support/Adobe/Lightroom/Modules`
36 | In Mac OS (all users) | `/Library/Application Support/Adobe/Lightroom/Modules`
37 | In Windows XP | `C:\Documents and Users\username\Application Data\Adobe\Lightroom\Modules`
38 | In Windows 7 / Vista | `C:\Users\username\AppData\Roaming\Adobe\Lightroom\Modules`
39 |
40 | Lightroom will automatically detect the plug-in the next time you start Lightroom.
41 |
42 |
43 | Note: If you follow the instructions to add the plug-in automatically, the remove button of the Plug-in Manager will be grayed out. You must manually delete the plug-in from the modules folder of Lightroom. To do this, select Day One Exporter plug-in and press `Show in Finder` and delete `dayone.lrplugin`.
44 |
45 | 
46 |
47 |
48 | ## Usage
49 |
50 | To use this plug-in, select the picture(s) that you want to export and press the `Export` button in the Library module of Lightroom. In the export dialog box, change the `Export To:` drop down menu to `Day One`.
51 |
52 | 
53 |
54 | ### Journal Location Options
55 | This option allows you to choose where your Day One journal is located. If you have your Day One journal in a special location, then you can select the last option, and specify where the journal is located. The Dropbox option assumes that you are using the default Dropbox location.
56 |
57 | ### Entry Settings
58 |
59 | **Use picture's time**: This will use the time that the picture was taken as the creation time for the entry.
60 |
61 | **Star Entry**: This will star all entries that are created by this export.
62 |
63 | **Use picture's keywords as tags**: This will use Lightroom's keywords as tags in the Day One entry.
64 |
65 | **Apply specific tags**: This allows you to add specific tags to all entries that are exported. This might be useful if you want to keep track of the source of pictures in your Day One journal. Each tag must be comma separated for this to work.
66 |
67 | Warning: Pictures that are exported can be extremely large and take up a lot of space in iCloud or Dropbox. You can use the normal `Image Sizing` options to scale down the picture.
68 |
69 | ## Acknowledgment
70 | Thanks to [tcjennings](https://github.com/tcjennings/LUA-RFC-4122-UUID-Generator) for the UUID4 generator.
71 |
72 |
73 | [1]: https://github.com/philipbl/Day-One-Lightroom-Plugin/archive/master.zip
74 |
--------------------------------------------------------------------------------
/dayone.lrdevplugin/ExportDialogSections.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (c) 2013, Philip Lundrigan
2 | -- All rights reserved.
3 | -- BSD License
4 |
5 | ExportDialogSections = {}
6 |
7 | LrPathUtils = import 'LrPathUtils'
8 | dayOne2Path = LrPathUtils.standardizePath('~/Library/Group Containers/5U8NS4GX82.dayoneapp2/Data/Auto Import/Default Journal.dayone')
9 | icloudPath = LrPathUtils.standardizePath('~/Library/Mobile Documents/5U8NS4GX82~com~dayoneapp~dayone/Documents/Journal_dayone')
10 | dropboxPath = LrPathUtils.getStandardFilePath('home') .. LrPathUtils.standardizePath('/Dropbox/Apps/Day One/Journal.dayone')
11 | activityList = {'Stationary', 'Walking', 'Running', 'Biking', 'Eating', 'Automotive', 'Flying'}
12 |
13 | function ExportDialogSections.sectionsForTopOfDialog( viewFactory, propertyTable )
14 | local LrDialogs = import "LrDialogs"
15 | local LrView = import "LrView"
16 | local LrPathUtils = import 'LrPathUtils'
17 | local LrFileUtils = import 'LrFileUtils'
18 |
19 | local bind = LrView.bind
20 | local share = LrView.share
21 |
22 | local function iCloudExists()
23 | return LrFileUtils.exists( icloudPath )
24 | end
25 |
26 | return {
27 | {
28 | title = "Journal Location",
29 | synopsis = bind 'journal_type',
30 |
31 | viewFactory:row {
32 | spacing = viewFactory:control_spacing(),
33 | viewFactory:radio_button {
34 | title = 'Day One 2',
35 | value = bind 'journal_type',
36 | checked_value = 'Day One 2',
37 | enabled = iCloudExists(),
38 | action = function ()
39 | propertyTable.custom = false
40 | propertyTable.journal_type = 'Day One 2'
41 | propertyTable.path = dayOne2Path
42 | end,
43 | },
44 | },
45 |
46 | viewFactory:row {
47 | spacing = viewFactory:control_spacing(),
48 | viewFactory:radio_button {
49 | title = 'iCloud',
50 | value = bind 'journal_type',
51 | checked_value = 'iCloud',
52 | enabled = iCloudExists(),
53 | action = function ()
54 | propertyTable.custom = false
55 | propertyTable.journal_type = 'iCloud'
56 | propertyTable.path = icloudPath
57 | end,
58 | },
59 | },
60 |
61 | viewFactory:row {
62 | spacing = viewFactory:control_spacing(),
63 | viewFactory:radio_button {
64 | title = 'Dropbox',
65 | value = bind 'journal_type',
66 | checked_value = 'Dropbox',
67 | action = function ()
68 | propertyTable.custom = false
69 | propertyTable.journal_type = 'Dropbox'
70 | propertyTable.path = dropboxPath
71 | end,
72 | },
73 | },
74 |
75 | viewFactory:row {
76 | spacing = viewFactory:control_spacing(),
77 | viewFactory:radio_button {
78 | title = 'Custom',
79 | value = bind 'journal_type',
80 | checked_value = 'Custom',
81 | action = function ()
82 | propertyTable.custom = true
83 | propertyTable.journal_type = 'Custom'
84 | propertyTable.path = propertyTable.custom_path
85 | end,
86 | },
87 |
88 | viewFactory:push_button {
89 | title = "Browse",
90 | enabled = bind 'custom',
91 | action = function ()
92 | local location = LrDialogs.runOpenPanel({
93 | title = "Day One Journal Location",
94 | canChooseDirectories = true,
95 | allowsMultipleSelection = false,
96 | })[1]
97 |
98 | propertyTable.custom_path = location
99 | propertyTable.path = propertyTable.custom_path
100 | end
101 | },
102 |
103 | },
104 |
105 | viewFactory:row {
106 | spacing = viewFactory:control_spacing(),
107 | viewFactory:static_text {
108 | title = 'Path: ',
109 | },
110 |
111 | viewFactory:static_text {
112 | title = bind { key = 'path', object = propertyTable },
113 | width = 500,
114 | truncation = 'head',
115 | },
116 | },
117 | },
118 |
119 | {
120 | title = "Entry Settings",
121 |
122 | viewFactory:row {
123 | spacing = viewFactory:control_spacing(),
124 | viewFactory:checkbox {
125 | title = "Use picture's time",
126 | value = bind 'use_time'
127 | },
128 | },
129 |
130 | viewFactory:row {
131 | spacing = viewFactory:control_spacing(),
132 | viewFactory:checkbox {
133 | title = "Use picture's location",
134 | value = bind 'use_location'
135 | },
136 | viewFactory:static_text {
137 | title = "(if GPS coordinates are present)",
138 | enabled = false,
139 | },
140 | },
141 |
142 | viewFactory:row {
143 | spacing = viewFactory:control_spacing(),
144 | viewFactory:checkbox {
145 | title = "Star entry",
146 | value = bind 'star'
147 | },
148 | },
149 |
150 | viewFactory:row {
151 | spacing = viewFactory:control_spacing(),
152 | viewFactory:checkbox {
153 | title = "Use picture's keywords as tags",
154 | value = bind 'use_keywords'
155 | },
156 | },
157 |
158 | viewFactory:row {
159 | spacing = viewFactory:control_spacing(),
160 | viewFactory:checkbox {
161 | title = "Apply specific tags:",
162 | value = bind 'use_specific_tags'
163 | },
164 | viewFactory:edit_field {
165 | value = bind 'tags',
166 | enabled = bind 'use_specific_tags',
167 | immediate = true,
168 | },
169 | viewFactory:static_text {
170 | title = "(comma separated)",
171 | enabled = false,
172 | },
173 | },
174 |
175 | viewFactory:row {
176 | spacing = viewFactory:control_spacing(),
177 | viewFactory:checkbox {
178 | title = "Apply motion activity:",
179 | value = bind 'use_activity'
180 | },
181 | viewFactory:combo_box {
182 | value = bind 'activity',
183 | items = activityList,
184 | auto_completion = true,
185 | enabled = bind 'use_activity',
186 | immediate = false,
187 | validate = function( view, value )
188 | for _, v in pairs( activityList ) do
189 | if v == value then
190 | return true, value, ""
191 | end
192 | end
193 | return false, value, "Must be valid activity:\nStationary, Walking, Running, Biking, Eating, Automotive, Flying"
194 | end
195 | },
196 | },
197 | },
198 | }
199 | end
200 |
--------------------------------------------------------------------------------
/dayone.lrdevplugin/ExportTask.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (c) 2013, Philip Lundrigan
2 | -- All rights reserved.
3 | -- BSD License
4 |
5 | local random = math.random
6 | local LrPathUtils = import 'LrPathUtils'
7 | local LrFileUtils = import 'LrFileUtils'
8 | local LrDialogs = import 'LrDialogs'
9 | local LrDate = import 'LrDate'
10 | local LrStringUtils = import 'LrStringUtils'
11 | local LrXml = import 'LrXml'
12 | local uuid4= (loadfile(LrPathUtils.child(_PLUGIN.path, "uuid4.lua")))()
13 |
14 | local function uuid()
15 | local uuid = uuid4.getUUID()
16 | return string.gsub( uuid, '-', function (c)
17 | return ''
18 | end)
19 | end
20 |
21 | local function split( str, delimiter )
22 | local result = { }
23 | local from = 1
24 | local delim_from, delim_to = string.find( str, delimiter, from )
25 | while delim_from do
26 | table.insert( result, LrStringUtils.trimWhitespace( string.sub( str, from , delim_from-1 ) ) )
27 | from = delim_to + 1
28 | delim_from, delim_to = string.find( str, delimiter, from )
29 | end
30 | table.insert( result, LrStringUtils.trimWhitespace( string.sub( str, from ) ) )
31 | return result
32 | end
33 |
34 | local function validJournalPath( path )
35 | if not LrFileUtils.exists( path ) then
36 | return false, "Journal directory does not exist."
37 | elseif not LrFileUtils.exists( LrPathUtils.child(path, 'entries') ) then
38 | -- This directory should really be in here, if it is a valid journal
39 | -- Let's just error out and make the user pick a different directory
40 | return false, "\"entries\" directory does not exist."
41 | elseif not LrFileUtils.exists( LrPathUtils.child(path, 'photos') ) then
42 | -- When the user has not added a photo yet, the "photos" directory does not exist
43 | -- Let's just create it for them.
44 | LrFileUtils.createDirectory( LrPathUtils.child(path, 'photos') )
45 | end
46 |
47 | return true, ""
48 | end
49 |
50 | local function getUniqueUUID( path )
51 | local fileName = uuid()
52 |
53 | while LrFileUtils.exists(
54 | LrPathUtils.child(
55 | LrPathUtils.child( path, 'entries' ), fileName ) .. '.doentry' ) do
56 | fileName = uuid()
57 | end
58 |
59 | return fileName
60 | end
61 |
62 | local function getLocation( gps )
63 | local LrHttp = import "LrHttp"
64 |
65 | local lat = gps.latitude
66 | local long = gps.longitude
67 |
68 | local url = "http://maps.googleapis.com/maps/api/geocode/xml?latlng=" .. lat .. "," .. long .. "&sensor=true"
69 | local xml = LrHttp.get( url )
70 |
71 | root = LrXml.parseXml( xml )
72 | status = root:childAtIndex( 1 ):text()
73 |
74 | local xsltString = [[
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | ,
85 |
86 |
87 | ]]
88 |
89 | local location = split( root:transform( xsltString ), ',' )
90 |
91 | local results = {}
92 | results.placeName = location[1]
93 | results.locality = location[2]
94 | results.adminArea = location[4]
95 | results.country = location[5]
96 | results.latitude = lat
97 | results.longitude = long
98 |
99 | return results
100 | end
101 |
102 | local function formatTime( time )
103 | tz, ds = LrDate.timeZone()
104 | if ds then
105 | time = time - tz - 3600
106 | else
107 | time = time - tz
108 | end
109 |
110 | local date = LrDate.timeToUserFormat( time, "%Y-%m-%d" )
111 | local time = LrDate.timeToUserFormat( time, "%H:%M:%S" )
112 | return date .. 'T' .. time .. 'Z'
113 | end
114 |
115 | local function generateEntry(date, starred, location, tags, uuid, activity)
116 |
117 | local entryString = [[
118 |
119 |
120 |
121 | %s
122 | Creation Date
123 | %s
124 | Entry Text
125 | %s
126 | Starred
127 | <%s/>%s
128 | UUID
129 | %s
130 |
131 |
132 | ]]
133 |
134 | -- take care of activity if necessary
135 | local activityString = ''
136 | if activity ~= nil then
137 | activityString = [[
138 |
139 | Activity
140 | %s]]
141 |
142 | activityString = string.format( activityString, activity)
143 | end
144 |
145 | -- take care of location if necessary
146 | local locationString = ''
147 | if location ~= nil then
148 | locationString = [[
149 |
150 | Location
151 |
152 | Administrative Area
153 | %s
154 | Country
155 | %s
156 | Latitude
157 | %s
158 | Locality
159 | %s
160 | Longitude
161 | %s
162 | Place Name
163 | %s
164 | ]]
165 |
166 | locationString = string.format( locationString,
167 | location.adminArea,
168 | location.country,
169 | location.latitude,
170 | location.locality,
171 | location.longitude,
172 | location.placeName )
173 | end
174 |
175 | -- take care of tags if necessary
176 | tag = ''
177 | if next(tags) ~= nil then
178 | tag = tag .. '\n\t'
179 |
180 | for key,value in pairs(tags) do
181 | tag = tag .. '\n\t\t' .. key .. ''
182 | end
183 |
184 | tag = tag .. '\n\t'
185 | else
186 | tag = '\n\t'
187 | end
188 |
189 | tagString = [[
190 |
191 | Tags%s]]
192 |
193 | tagString = string.format( tagString, tag )
194 |
195 | entryString = string.format( entryString,
196 | activityString,
197 | formatTime( date ),
198 | locationString,
199 | starred,
200 | tagString,
201 | uuid )
202 |
203 | return entryString
204 | end
205 |
206 | local function createEntry( exportParams, photo, uuid )
207 | local date = exportParams.use_time and
208 | photo:getRawMetadata("dateTimeOriginal") or
209 | LrDate.currentTime()
210 |
211 | -- get the correct path
212 | local entries = LrPathUtils.child( exportParams.path, 'entries' )
213 | local path = LrPathUtils.child( LrPathUtils.standardizePath( entries ), uuid .. '.doentry' )
214 |
215 | -- get the keywords
216 | local oldKeywords = exportParams.use_keywords and
217 | split( photo:getFormattedMetadata("keywordTags"), ',' ) or
218 | {}
219 |
220 | local newKeywords = exportParams.use_specific_tags and
221 | split( exportParams.tags, ',' ) or
222 | {}
223 |
224 | local activity = exportParams.use_activity and
225 | exportParams.activity or
226 | nil
227 |
228 | -- join two lists together
229 | local tags = {}
230 | for _, l in ipairs(oldKeywords) do
231 | if l ~= "" then
232 | tags[l] = true
233 | end
234 | end
235 |
236 | for _, l in ipairs(newKeywords) do
237 | if l ~= "" then
238 | tags[l] = true
239 | end
240 | end
241 |
242 | -- get location
243 | local location = nil
244 | if exportParams.use_location and photo:getRawMetadata("gps") then
245 | location = getLocation( photo:getRawMetadata("gps") )
246 | end
247 |
248 | -- write entry
249 | local f = io.open( path, "w" )
250 | f:write( generateEntry( date, exportParams.star, location, tags, uuid, activity ))
251 | f:close()
252 |
253 | end
254 |
255 | local function createPhoto( exportParams, photoPath, uuid )
256 | local photos = LrPathUtils.child( exportParams.path, 'photos' )
257 | LrFileUtils.copy( photoPath, LrPathUtils.child(LrPathUtils.standardizePath(photos), uuid .. '.jpg') )
258 | end
259 |
260 |
261 |
262 | ExportTask = {}
263 |
264 | function ExportTask.processRenderedPhotos( functionContext, exportContext )
265 |
266 | local exportSession = exportContext.exportSession
267 | local exportParams = exportContext.propertyTable
268 |
269 | local nPhotos = exportSession:countRenditions()
270 | local progressScope = exportContext:configureProgress {
271 | title = nPhotos > 1 and
272 | "Adding " .. nPhotos .. " photos to Day One" or
273 | "Adding one photo to Day One",
274 | }
275 |
276 | -- Check if selected journal location exists
277 | valid, errorMessage = validJournalPath( exportParams.path )
278 | if not valid then
279 | LrDialogs.showError( "Something is wrong with the journal location \n(" .. exportParams.path .. ")\n you selected. " .. errorMessage)
280 | return
281 | end
282 |
283 | -- Iterate through photo renditions.
284 | for _, rendition in exportContext:renditions{ stopIfCanceled = true } do
285 |
286 | -- Wait for next photo to render.
287 | local success, pathOrMessage = rendition:waitForRender()
288 |
289 | if progressScope:isCanceled() then break end
290 |
291 | if success then
292 | local uuid = getUniqueUUID( exportParams.path )
293 |
294 | createEntry( exportParams, rendition.photo, uuid )
295 | createPhoto( exportParams, pathOrMessage, uuid )
296 |
297 | -- clean up
298 | LrFileUtils.delete( pathOrMessage )
299 |
300 | else
301 | LrDialogs.message( pathOrMessage )
302 | end
303 |
304 | end
305 | end
306 |
--------------------------------------------------------------------------------