Play images and video from Synology PhotoStation server

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. --[[----------------------------------------------------------------------------
  2. PSPhotoStationAPI.lua
  3. This file is part of Photo StatLr - Lightroom plugin.
  4. Copyright(c) 2017, Martin Messmer
  5. Photo Station Upload primitives:
  6. - initialize
  7. - login
  8. - logout
  9. - listAlbum
  10. - movePic
  11. - deletePic
  12. - sortPics
  13. - addPhotoComments
  14. - getPhotoComments
  15. - getPhotoExifs
  16. - getTags
  17. - getPhotoTags
  18. - editPhoto
  19. - createSharedAlbum
  20. - editSharedAlbum
  21. - listSharedAlbum
  22. - addPhotosToSharedAlbum
  23. - removePhotosFromSharedAlbum
  24. Photo StatLr is free software: you can redistribute it and/or modify
  25. it under the terms of the GNU General Public License as published by
  26. the Free Software Foundation, either version 3 of the License, or
  27. (at your option) any later version.
  28. Photo StatLr is distributed in the hope that it will be useful,
  29. but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  31. GNU General Public License for more details.
  32. You should have received a copy of the GNU General Public License
  33. along with Photo StatLr. If not, see <http://www.gnu.org/licenses/>.
  34. ]]
  35. --------------------------------------------------------------------------------
  36. -- Lightroom API
  37. local LrFileUtils = import 'LrFileUtils'
  38. local LrPathUtils = import 'LrPathUtils'
  39. local LrHttp = import 'LrHttp'
  40. local LrDate = import 'LrDate'
  41. require "PSUtilities"
  42. --====== local functions =====================================================--
  43. --[[
  44. callSynoAPI (h, synoAPI, formData)
  45. calls the named synoAPI with the respective parameters in formData
  46. returns nil, on http error
  47. returns the decoded JSON response as table on success
  48. ]]
  49. local function callSynoAPI (h, synoAPI, formData)
  50. local postHeaders = {
  51. { field = 'Content-Type', value = 'application/x-www-form-urlencoded' },
  52. }
  53. local postBody = 'api=' .. synoAPI .. '&' .. formData
  54. if synoAPI == 'SYNO.PhotoStation.Auth' then
  55. writeLogfile(4, "callSynoAPI: LrHttp.post(" .. h.serverUrl .. h.psWebAPI .. h.apiInfo[synoAPI].path .. ",...)\n")
  56. else
  57. writeLogfile(4, string.format("callSynoAPI: LrHttp.post(%s%s%s, api=%s&%s\n", h.serverUrl, h.psWebAPI, h.apiInfo[synoAPI].path, synoAPI, formData))
  58. end
  59. local respBody, respHeaders = LrHttp.post(h.serverUrl .. h.psWebAPI .. h.apiInfo[synoAPI].path, postBody, postHeaders, 'POST', h.serverTimeout, string.len(postBody))
  60. if not respBody then
  61. writeTableLogfile(3, 'respHeaders', respHeaders)
  62. if respHeaders then
  63. writeLogfile(3, string.format("Error %s on http request: %s\n",
  64. ifnil(respHeaders["error"].errorCode, 'Unknown'),
  65. trim(ifnil(respHeaders["error"].name, 'Unknown error description'))))
  66. local errorCode = tonumber(ifnil(respHeaders["error"].nativeCode, '1002'))
  67. return nil, errorCode
  68. else
  69. return nil, 1001
  70. end
  71. end
  72. writeLogfile(4, "Got Body:\n" .. respBody .. "\n")
  73. local respArray = JSON:decode(respBody)
  74. if not respArray then return nil, 1003 end
  75. if respArray.error then
  76. local errorCode = tonumber(respArray.error.code)
  77. writeLogfile(3, string.format('PSPhotoStationAPI.callSynoAPI: %s returns error %d\n', synoAPI, errorCode))
  78. return nil, errorCode
  79. end
  80. return respArray
  81. end
  82. --====== global functions ====================================================--
  83. PSPhotoStationAPI = {}
  84. ---------------------------------------------------------------------------------------------------------
  85. -- initialize: set serverUrl, loginPath and uploadPath
  86. function PSPhotoStationAPI.initialize(serverUrl, psPath, serverTimeout)
  87. local h = {} -- the handle
  88. local apiInfo = {}
  89. writeLogfile(4, "PSPhotoStationAPI.initialize(PhotoStationUrl=" .. serverUrl .. psPath .. ", Timeout=" .. serverTimeout .. ")\n")
  90. h.serverUrl = serverUrl
  91. h.serverTimeout = serverTimeout
  92. h.psAlbumRoot = psPath .. '#!Albums'
  93. h.psWebAPI = psPath .. 'webapi/'
  94. h.uploadPath = psPath .. 'include/asst_file_upload.php'
  95. -- bootstrap the apiInfo table
  96. apiInfo['SYNO.API.Info'] = {
  97. path = "query.php",
  98. minVersion = 1,
  99. maxVersion = 1,
  100. }
  101. h.apiInfo = apiInfo
  102. -- get all API paths via 'SYNO.API.Info'
  103. local formData =
  104. 'query=all&' ..
  105. 'method=query&' ..
  106. 'version=1&' ..
  107. 'ps_username='
  108. local respArray, errorCode = callSynoAPI (h, 'SYNO.API.Info', formData)
  109. if not respArray then return nil, errorCode end
  110. -- rewrite the apiInfo table with API infos retrieved via SYNO.API.Info
  111. h.apiInfo = respArray.data
  112. -- writeTableLogfile(4, 'apiInfo', h.apiInfo)
  113. return h
  114. end
  115. ---------------------------------------------------------------------------------------------------------
  116. -- login(h, username, passowrd)
  117. -- does, what it says
  118. function PSPhotoStationAPI.login(h, username, password)
  119. local formData = 'method=login&' ..
  120. 'version=1&' ..
  121. 'username=' .. urlencode(username) .. '&' ..
  122. 'password=' .. urlencode(password)
  123. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Auth', formData)
  124. if not respArray then return false, errorCode end
  125. return respArray.success
  126. end
  127. ---------------------------------------------------------------------------------------------------------
  128. -- logout(h)
  129. -- nothing to do here, invalidating the cookie would be perfect here
  130. function PSPhotoStationAPI.logout (h)
  131. return true
  132. end
  133. ---------------------------------------------------------------------------------------------------------
  134. -- listAlbum: returns all photos/videos and optionally albums in a given album
  135. -- returns
  136. -- albumItems: table of photo infos, if success, otherwise nil
  137. -- errorcode: errorcode, if not success
  138. function PSPhotoStationAPI.listAlbum(h, dstDir, listItems)
  139. -- recursive doesn't seem to work
  140. local formData = 'method=list&' ..
  141. 'version=1&' ..
  142. 'id=' .. PSPhotoStationUtils.getAlbumId(dstDir) .. '&' ..
  143. 'type=' .. listItems .. '&' ..
  144. 'offset=0&' ..
  145. 'limit=-1&' ..
  146. 'recursive=false&'..
  147. 'additional=album_permission,photo_exif'
  148. -- 'additional=album_permission,photo_exif,video_codec,video_quality,thumb_size,file_location'
  149. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Album', formData)
  150. if not respArray then return nil, errorCode end
  151. writeTableLogfile(4, 'listAlbum(' .. dstDir .. ')', respArray.data.items)
  152. return respArray.data.items
  153. end
  154. ---------------------------------------------------------------------------------------------------------
  155. -- deletePic (h, dstFilename, isVideo)
  156. function PSPhotoStationAPI.deletePic (h, dstFilename, isVideo)
  157. local formData = 'method=delete&' ..
  158. 'version=1&' ..
  159. 'id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo) .. '&'
  160. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Photo', formData)
  161. if not respArray and errorCode ~= 101 then return false, errorCode end
  162. writeLogfile(3, string.format('deletePic(%s) returns OK (errorCode was %d)\n', dstFilename, ifnil(errorCode, 0)))
  163. return respArray.success
  164. end
  165. ---------------------------------------------------------------------------------------------------------
  166. -- movePic (h, srcFilename, dstAlbum, isVideo)
  167. function PSPhotoStationAPI.movePic(h, srcFilename, dstAlbum, isVideo)
  168. local formData = 'method=copy&' ..
  169. 'version=1&' ..
  170. 'mode=move&' ..
  171. 'duplicate=ignore&' ..
  172. 'id=' .. PSPhotoStationUtils.getPhotoId(srcFilename, isVideo) .. '&' ..
  173. 'sharepath=' .. PSPhotoStationUtils.getAlbumId(dstAlbum)
  174. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Photo', formData)
  175. if not respArray then return false, errorCode end
  176. writeLogfile(3, string.format('movePic(%s, %s) returns OK\n', srcFilename, dstAlbum))
  177. return respArray.success
  178. end
  179. ---------------------------------------------------------------------------------------------------------
  180. -- deleteAlbum(h, albumPath)
  181. function PSPhotoStationAPI.deleteAlbum (h, albumPath)
  182. local formData = 'method=delete&' ..
  183. 'version=1&' ..
  184. 'id=' .. PSPhotoStationUtils.getAlbumId(albumPath) .. '&'
  185. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Album', formData)
  186. if not respArray then return false, errorCode end
  187. writeLogfile(3, string.format('deleteAlbum(%s) returns OK\n', albumPath))
  188. return respArray.success
  189. end
  190. ---------------------------------------------------------------------------------------------------------
  191. -- sortPics (h, albumPath, sortedPhotos)
  192. function PSPhotoStationAPI.sortPics (h, albumPath, sortedPhotos)
  193. local formData = 'method=arrangeitem&' ..
  194. 'version=1&' ..
  195. 'offset=0&' ..
  196. 'limit='.. #sortedPhotos .. '&' ..
  197. 'id=' .. PSPhotoStationUtils.getAlbumId(albumPath) .. '&'
  198. local i, photoPath, item_ids = {}
  199. for i, photoPath in ipairs(sortedPhotos) do
  200. if i == 1 then
  201. item_ids = PSPhotoStationUtils.getPhotoId(sortedPhotos[i])
  202. else
  203. item_ids = item_ids .. ',' .. PSPhotoStationUtils.getPhotoId(sortedPhotos[i])
  204. end
  205. end
  206. formData = formData .. 'item_id=' .. item_ids
  207. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Album', formData)
  208. if not respArray then return false, errorCode end
  209. writeLogfile(3, string.format('sortPics(%s) returns OK.\n', albumPath))
  210. return respArray.success
  211. end
  212. ---------------------------------------------------------------------------------------------------------
  213. -- addPhotoComment (h, dstFilename, isVideo, comment, username)
  214. function PSPhotoStationAPI.addPhotoComment (h, dstFilename, isVideo, comment, username)
  215. local formData = 'method=create&' ..
  216. 'version=1&' ..
  217. 'id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo) .. '&' ..
  218. 'name=' .. username .. '&' ..
  219. 'comment='.. urlencode(comment)
  220. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Comment', formData)
  221. if not respArray then return false, errorCode end
  222. writeLogfile(3, string.format('addPhotoComment(%s, %s, %s) returns OK.\n', dstFilename, comment, username))
  223. return respArray.success
  224. end
  225. ---------------------------------------------------------------------------------------------------------
  226. -- getPhotoComments (h, dstFilename, isVideo)
  227. function PSPhotoStationAPI.getPhotoComments (h, dstFilename, isVideo)
  228. local formData = 'method=list&' ..
  229. 'version=1&' ..
  230. 'id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo)
  231. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Comment', formData)
  232. if not respArray then return false, errorCode end
  233. writeLogfile(3, string.format('getPhotoComments(%s) returns OK.\n', dstFilename))
  234. return respArray.data.comments
  235. end
  236. --[[ currently not needed
  237. ---------------------------------------------------------------------------------------------------------
  238. -- addSharedPhotoComment (h, dstFilename, isVideo, comment, username, sharedAlbumName)
  239. function PSPhotoStationAPI.addSharedPhotoComment (h, dstFilename, isVideo, comment, username, sharedAlbumName)
  240. local formData = 'method=add_comment&' ..
  241. 'version=1&' ..
  242. 'item_id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo) .. '&' ..
  243. 'name=' .. username .. '&' ..
  244. 'comment='.. urlencode(comment) ..'&' ..
  245. 'public_share_id=' .. PSPhotoStationUtils.getSharedAlbumShareId(h, sharedAlbumName)
  246. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.AdvancedShare', formData)
  247. if not respArray then return false, errorCode end
  248. writeLogfile(3, string.format('addSharedPhotoComment(%s, %s, %s, %s) returns OK.\n', dstFilename, sharedAlbumName, comment, username))
  249. return respArray.success
  250. end
  251. ]]
  252. ---------------------------------------------------------------------------------------------------------
  253. -- getSharedPhotoComments (h, sharedAlbumName, dstFilename, isVideo)
  254. function PSPhotoStationAPI.getSharedPhotoComments (h, sharedAlbumName, dstFilename, isVideo)
  255. local formData = 'method=list_comment&' ..
  256. 'version=1&' ..
  257. 'offset=0&' ..
  258. 'limit=-1&' ..
  259. 'item_id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo) .. '&' ..
  260. 'public_share_id=' .. PSPhotoStationUtils.getSharedAlbumShareId(h, sharedAlbumName)
  261. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.AdvancedShare', formData)
  262. if not respArray then return false, errorCode end
  263. if respArray.data then
  264. writeLogfile(3, string.format('getSharedPhotoComments(%s, %s) returns %d comments.\n', dstFilename, sharedAlbumName, #respArray.data))
  265. else
  266. writeLogfile(3, string.format('getSharedPhotoComments(%s, %s) returns no comments.\n', dstFilename, sharedAlbumName))
  267. end
  268. return respArray.data
  269. end
  270. ---------------------------------------------------------------------------------------------------------
  271. -- getSharedAlbumCommentList (h, sharedAlbumName)
  272. function PSPhotoStationAPI.getSharedAlbumCommentList (h, sharedAlbumName)
  273. local formData = 'method=list_log&' ..
  274. 'version=1&' ..
  275. 'offset=0&' ..
  276. 'limit=-1&' ..
  277. 'category=comment&' ..
  278. 'public_share_id=' .. PSPhotoStationUtils.getSharedAlbumShareId(h, sharedAlbumName)
  279. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.AdvancedShare', formData)
  280. if not respArray then return false, errorCode end
  281. if respArray.data then
  282. writeLogfile(3, string.format('getSharedAlbumCommentList(%s) returns %d comments.\n', sharedAlbumName, respArray.data.total))
  283. else
  284. writeLogfile(3, string.format('getSharedAlbumCommentList(%s) returns no comments.\n', sharedAlbumName))
  285. end
  286. return respArray.data.data
  287. end
  288. ---------------------------------------------------------------------------------------------------------
  289. -- getPhotoExifs (h, dstFilename, isVideo)
  290. function PSPhotoStationAPI.getPhotoExifs (h, dstFilename, isVideo)
  291. local formData = 'method=getexif&' ..
  292. 'version=1&' ..
  293. 'id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo)
  294. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Photo', formData)
  295. if not respArray then return false, errorCode end
  296. writeLogfile(3, string.format('getPhotoExifs(%s) returns %d exifs.\n', dstFilename, respArray.data.total))
  297. return respArray.data.exifs
  298. end
  299. ---------------------------------------------------------------------------------------------------------
  300. -- getTags (h, type)
  301. -- get table of tagId/tagString mappings for given type: desc, people, geo
  302. function PSPhotoStationAPI.getTags(h, type)
  303. local formData = 'method=list&' ..
  304. 'version=1&' ..
  305. 'type=' .. type .. '&' ..
  306. -- 'additional=info&' ..
  307. 'offset=0&' ..
  308. 'limit=-1'
  309. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Tag', formData)
  310. if not respArray then return false, errorCode end
  311. writeLogfile(3, string.format('getTags returns %d tags.\n', respArray.data.total))
  312. return respArray.data.tags
  313. end
  314. ---------------------------------------------------------------------------------------------------------
  315. -- createTag (h, type, name)
  316. -- create a new tagId/tagString mapping of or given type: desc, people, geo
  317. function PSPhotoStationAPI.createTag(h, type, name)
  318. local formData = 'method=create&' ..
  319. 'version=1&' ..
  320. 'type=' .. type .. '&' ..
  321. 'name=' .. urlencode(name)
  322. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Tag', formData)
  323. if not respArray then return false, errorCode end
  324. writeLogfile(3, string.format('createTag(%s, %s) returns tagId %s.\n', type, name, respArray.data.id))
  325. return respArray.data.id
  326. end
  327. ---------------------------------------------------------------------------------------------------------
  328. -- getPhotoTags (h, dstFilename, isVideo)
  329. -- get table of tags (general,people,geo) of a photo
  330. function PSPhotoStationAPI.getPhotoTags(h, dstFilename, isVideo)
  331. local formData = 'method=list&' ..
  332. 'version=1&' ..
  333. 'type=people,geo,desc&' ..
  334. 'additional=info&' ..
  335. 'id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo)
  336. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.PhotoTag', formData)
  337. if not respArray then return false, errorCode end
  338. writeLogfile(3, string.format('getPhotoTags(%s) returns %d tags.\n', dstFilename, #respArray.data.tags))
  339. return respArray.data.tags
  340. end
  341. ---------------------------------------------------------------------------------------------------------
  342. -- addPhotoTag (h, dstFilename, isVideo, tagId)
  343. -- add a new tag (general,people,geo) to a photo
  344. function PSPhotoStationAPI.addPhotoTag(h, dstFilename, isVideo, type, tagId)
  345. local formData = 'method=' .. type .. '_tag&' ..
  346. 'version=1&' ..
  347. 'tag_id=' .. tagId .. '&' ..
  348. 'id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo)
  349. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.PhotoTag', formData)
  350. if not respArray then return false, errorCode end
  351. writeLogfile(3, string.format('addPhotoTag(%s) returns %d item_tag_ids.\n', dstFilename, #respArray.data.item_tag_ids))
  352. return respArray.data.item_tag_ids
  353. end
  354. ---------------------------------------------------------------------------------------------------------
  355. -- editPhoto (h, dstFilename, isVideo, attrValPairs)
  356. -- edit specific metadata field of a photo
  357. function PSPhotoStationAPI.editPhoto(h, dstFilename, isVideo, attrValPairs)
  358. local formData = 'method=edit&' ..
  359. 'version=1&' ..
  360. 'id=' .. PSPhotoStationUtils.getPhotoId(dstFilename, isVideo)
  361. local logMessage = ''
  362. for i = 1, #attrValPairs do
  363. formData = formData .. '&' .. attrValPairs[i].attribute .. '=' .. attrValPairs[i].value
  364. logMessage = logMessage .. ', ' .. attrValPairs[i].attribute .. '=' .. attrValPairs[i].value
  365. end
  366. local success, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Photo', formData)
  367. if not success then return false, errorCode end
  368. writeLogfile(3, string.format('editPhoto(%s,%s) returns OK.\n', dstFilename, logMessage))
  369. return true
  370. end
  371. ---------------------------------------------------------------------------------------------------------
  372. -- getSharedAlbums (h)
  373. -- get table of sharedAlbumId/sharedAlbumName mappings
  374. function PSPhotoStationAPI.getSharedAlbums(h)
  375. local formData = 'method=list&' ..
  376. 'version=1&' ..
  377. 'additional=public_share&' ..
  378. 'offset=0&' ..
  379. 'limit=-1'
  380. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.SharedAlbum', formData)
  381. if not respArray then return nil, errorCode end
  382. writeLogfile(3, string.format('getSharedAlbums() returns %d albums.\n', respArray.data.total))
  383. return respArray.data.items
  384. end
  385. --[[
  386. ---------------------------------------------------------------------------------------------------------
  387. -- getSharedAlbumInfo (h, sharedAlbumId)
  388. -- get infos for the given Shared Album
  389. function PSPhotoStationAPI.getSharedAlbumInfo(h, sharedAlbumId)
  390. local formData = 'method=getinfo&' ..
  391. 'version=1&' ..
  392. 'additional=public_share&' ..
  393. 'id=' .. sharedAlbumId
  394. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.SharedAlbum', formData)
  395. if not respArray then return nil, errorCode end
  396. writeLogfile(3, string.format('getSharedAlbumInfo() returns %d albums.\n', #respArray.data.shared_albums))
  397. return respArray.data.shared_albums[1];
  398. end
  399. ]]
  400. ---------------------------------------------------------------------------------------------------------
  401. -- createSharedAlbum(h, name)
  402. function PSPhotoStationAPI.createSharedAlbum(h, name)
  403. local formData = 'method=create&' ..
  404. 'version=1&' ..
  405. -- 'item_id=<photo_id>&' ..
  406. 'name=' .. urlencode(name)
  407. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.SharedAlbum', formData)
  408. if not respArray then return false, errorCode end
  409. writeLogfile(3, string.format('createSharedAlbum(%s) returns sharedAlbumId %s.\n', name, respArray.data.id))
  410. return respArray.data.id
  411. end
  412. ---------------------------------------------------------------------------------------------------------
  413. -- editSharedAlbum(h, sharedAlbumName, sharedAlbumAttributes)
  414. function PSPhotoStationAPI.editSharedAlbum(h, sharedAlbumName, sharedAlbumAttributes)
  415. local numAttributes = 0
  416. local formData = 'method=edit_public_share&' ..
  417. 'version=1&' ..
  418. 'id=' .. PSPhotoStationUtils.getSharedAlbumId(h, sharedAlbumName)
  419. for attr, value in pairs(sharedAlbumAttributes) do
  420. formData = formData .. '&' .. attr .. '=' .. urlencode(tostring(value))
  421. numAttributes = numAttributes + 1
  422. end
  423. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.SharedAlbum', formData)
  424. if not respArray then return nil, errorCode end
  425. writeLogfile(3, string.format('editSharedAlbum(%s, %d attributes) returns shareId %s.\n', sharedAlbumName, numAttributes, respArray.data.shareid))
  426. return respArray.data
  427. end
  428. ---------------------------------------------------------------------------------------------------------
  429. -- listSharedAlbum: returns all photos/videos in a given shared album
  430. -- returns
  431. -- albumItems: table of photo infos, if success, otherwise nil
  432. -- errorcode: errorcode, if not success
  433. function PSPhotoStationAPI.listSharedAlbum(h, dstDir, listItems)
  434. local formData = 'method=list&' ..
  435. 'version=1&' ..
  436. 'filter_shared_album=' .. PSPhotoStationUtils.getSharedAlbumId(h, dstDir) .. '&' ..
  437. 'type=' .. listItems .. '&' ..
  438. 'offset=0&' ..
  439. 'limit=-1&' ..
  440. 'recursive=false&'..
  441. 'additional=photo_exif'
  442. -- 'additional=photo_exif,video_codec,video_quality,thumb_size'
  443. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.Photo', formData)
  444. if not respArray then return nil, errorCode end
  445. writeTableLogfile(4, 'listAlbum', respArray.data.items)
  446. return respArray.data.items
  447. end
  448. ---------------------------------------------------------------------------------------------------------
  449. -- PhotoStation.addPhotosToSharedAlbum(h, sharedAlbumName, photos)
  450. -- add photos to Shared Album
  451. function PSPhotoStationAPI.addPhotosToSharedAlbum(h, sharedAlbumName, photos)
  452. local photoIds = {}
  453. for i = 1, #photos do
  454. photoIds[i] = PSPhotoStationUtils.getPhotoId(photos[i].dstFilename, photos[i].isVideo)
  455. end
  456. local itemList = table.concat(photoIds, ',')
  457. local formData = 'method=add_items&' ..
  458. 'version=1&' ..
  459. 'id=' .. PSPhotoStationUtils.getSharedAlbumId(h, sharedAlbumName) .. '&' ..
  460. 'item_id=' .. itemList
  461. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.SharedAlbum', formData)
  462. if not respArray then return false, errorCode end
  463. writeLogfile(3, string.format('addPhotosToSharedAlbum(%s, %d photos) returns OK.\n', sharedAlbumName, #photos))
  464. return true
  465. end
  466. ---------------------------------------------------------------------------------------------------------
  467. -- PhotoStation.removePhotosFromSharedAlbum(h, sharedAlbumName, photos)
  468. -- remove photos from Shared Album
  469. function PSPhotoStationAPI.removePhotosFromSharedAlbum(h, sharedAlbumName, photos)
  470. local photoIds = {}
  471. for i = 1, #photos do
  472. photoIds[i] = PSPhotoStationUtils.getPhotoId(photos[i].dstFilename, photos[i].isVideo)
  473. end
  474. local itemList = table.concat(photoIds, ',')
  475. local formData = 'method=remove_items&' ..
  476. 'version=1&' ..
  477. 'id=' .. PSPhotoStationUtils.getSharedAlbumId(h, sharedAlbumName) .. '&' ..
  478. 'item_id=' .. itemList
  479. local respArray, errorCode = callSynoAPI (h, 'SYNO.PhotoStation.SharedAlbum', formData)
  480. if not respArray then return false, errorCode end
  481. writeLogfile(3, string.format('removePhotosFromSharedAlbum(%s,%d photos) returns OK.\n', sharedAlbumName, #photos))
  482. return true
  483. end