1. --!parent
  2. --!encoding=utf-8
  3.  
  4. --****************************************************************************
  5. -- @file lib "flickr"
  6. -- @author Valentin Schmidt
  7. -- @version 0.12
  8. -- @requires lib "curl" (+xtra "Curl")
  9. -- @requires lib "json"
  10. -- @requires lib "oauth"
  11. -- @requires lib "xmlparser" (+xtra "XmlParser") - only needed for photo_upload() which doesn't support JSON
  12. --****************************************************************************
  13.  
  14. global $
  15.  
  16. property _user_id
  17. property _err
  18. property _verbose
  19.  
  20. ----------------------------------------
  21. -- @constructor
  22. ----------------------------------------
  23. on new (me, consumer_data)
  24.  
  25.     -- libs
  26.     $.import("curl")
  27.     $.import("json")
  28.     $.import("oauth")
  29.     $.import("xmlparser")
  30.  
  31.     $.oauth.set_consumer_key(consumer_data[1], consumer_data[2])
  32.     me._err = []
  33.     me._verbose = FALSE
  34.     return me
  35. end
  36.  
  37. ----------------------------------------
  38. -- Toggles if curl prints connection details to stdout.
  39. -- @param {bool} flag
  40. ----------------------------------------
  41. on set_verbose (me, flag)
  42.     me._verbose = flag
  43.     $.oauth.set_verbose(flag)
  44. end
  45.  
  46. ----------------------------------------
  47. --
  48. ----------------------------------------
  49. on get_user_id (me)
  50.     return me._user_id
  51. end
  52.  
  53. ----------------------------------------
  54. -- Starts oauth by requesting a new oauth_token/oauth_token_secret pair.
  55. -- @return {propList}
  56. ----------------------------------------
  57. on get_request_token (me, callback_url)
  58.     u = "https://www.flickr.com/services/oauth/request_token"
  59.     ok = $.oauth.query_request_token(u, callback_url, me._err)
  60.     if ok then
  61.         -- authorize
  62.         request_token = $.oauth.get_request_token()[1]
  63.         perms = "delete"
  64.         u = "https://www.flickr.com/services/oauth/authorize?oauth_token="&request_token&"&perms="&perms
  65.         gotoNetPage(u) -- open in default browser
  66.         return ["stat": "ok"]
  67.     else
  68.         return ["stat": "fail", "code":me._err[1]]
  69.     end if
  70. end
  71.  
  72. ----------------------------------------
  73. -- Finishes oauth by passing verifier, saves access_token/access_token_secret.
  74. -- @param {string} verifier
  75. -- @return {propList}
  76. ----------------------------------------
  77. on get_access_token (me, verifier)
  78.     $.oauth.set_verifier(verifier)
  79.     u = "https://www.flickr.com/services/oauth/access_token"
  80.     ok = $.oauth.query_access_token(u, me._err)
  81.     if ok then
  82.         res = $.oauth.get_access_token()
  83.         return ["stat": "ok", "access_token": res[1], "access_token_secret": res[2]]
  84.     else
  85.         return ["stat": "fail", "code":me._err[1]]
  86.     end if
  87. end
  88.  
  89. ----------------------------------------
  90. -- Checks if specified access_token/access_token_secret are valid, saves current user's id.
  91. -- @param {string} access_token
  92. -- @param {string} access_token_secret
  93. -- @return {propList}
  94. ----------------------------------------
  95. on login (me, access_token, access_token_secret)
  96.     $.oauth.set_access_token(access_token, access_token_secret)
  97.     param_obj = [:]
  98.     param_obj["format"] = "json"
  99.     param_obj["nojsoncallback"] = "1"
  100.     param_obj["method"] = "flickr.test.login"
  101.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  102.     if integerP(res) then
  103.         return ["stat": "fail", "curl_error":curl_error(res)]
  104.     else if me._err[1]<200 or me._err[1]>=300 then
  105.         return ["stat": "fail", "code":me._err[1]]
  106.     else
  107.         json = res.readRawString(res.length)
  108.         res = $.json.decode(json)
  109.         me._user_id = res["user"]["id"]
  110.         return res
  111.     end if
  112. end
  113.  
  114. ----------------------------------------
  115. -- Returns the photosets belonging to the current user.
  116. -- @param {integer} [page=1]
  117. -- @param {integer} [per_page=500]
  118. -- @return {propList}
  119. ----------------------------------------
  120. on account_get_photosets (me, page, per_page)
  121.     param_obj = [:]
  122.     param_obj["format"] = "json"
  123.     param_obj["nojsoncallback"] = "1"
  124.     param_obj["method"] = "flickr.photosets.getList"
  125.     if not voidP(page) then
  126.         param_obj["page"] = page
  127.     end if
  128.     if not voidP(per_page) then
  129.         param_obj["per_page"] = per_page
  130.     end if
  131.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  132.     if integerP(res) then
  133.         return ["stat": "fail", "curl_error":curl_error(res)]
  134.     else if me._err[1]<200 or me._err[1]>=300 then
  135.         return ["stat": "fail", "code":me._err[1]]
  136.     else
  137.         json = res.readRawString(res.length)
  138.         return $.json.decode(json)
  139.     end if
  140. end
  141.  
  142. ----------------------------------------
  143. -- Sets the order of photosets for the calling user.
  144. -- @param {list} photoset_ids
  145. -- @return {propList}
  146. ----------------------------------------
  147. on account_order_photosets (me, photoset_ids)
  148.     param_obj = [:]
  149.     param_obj["format"] = "json"
  150.     param_obj["nojsoncallback"] = "1"
  151.     param_obj["method"] = "flickr.photosets.orderSets"
  152.     str = photoset_ids[1]
  153.     repeat with i = 2 to photoset_ids.count
  154.         put ","&photoset_ids[i] after str
  155.     end repeat
  156.     param_obj["photoset_ids"] = str
  157.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err, "post")
  158.     if integerP(res) then
  159.         return ["stat": "fail", "curl_error":curl_error(res)]
  160.     else if me._err[1]<200 or me._err[1]>=300 then
  161.         return ["stat": "fail", "code":me._err[1]]
  162.     else
  163.         json = res.readRawString(res.length)
  164.         return $.json.decode(json)
  165.     end if
  166. end
  167.  
  168. ----------------------------------------
  169. -- Gets the list of photos in a set, or photos that are not in any set for photoset_id=EMPTY.
  170. -- @param {string} photoset_id
  171. -- @param {integer} [page=1]
  172. -- @param {integer} [per_page=500]
  173. -- @return {propList}
  174. ----------------------------------------
  175. on photoset_get_photos (me, photoset_id, page, per_page)
  176.     param_obj = [:]
  177.     param_obj["format"] = "json"
  178.     param_obj["nojsoncallback"] = "1"
  179.     if photoset_id=EMPTY then
  180.         param_obj["method"] = "flickr.photos.getNotInSet"
  181.     else
  182.         param_obj["method"] = "flickr.photosets.getPhotos"
  183.         param_obj["photoset_id"] = photoset_id
  184.         param_obj["user_id"] = me._user_id
  185.     end if
  186.     if not voidP(page) then
  187.         param_obj["page"] = page
  188.     end if
  189.     if not voidP(per_page) then
  190.         param_obj["per_page"] = per_page
  191.     end if
  192.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  193.     if integerP(res) then
  194.         return ["stat": "fail", "curl_error":curl_error(res)]
  195.     else if me._err[1]<200 or me._err[1]>=300 then
  196.         return ["stat": "fail", "code":me._err[1]]
  197.     else
  198.         json = res.readRawString(res.length)
  199.         return $.json.decode(json)
  200.     end if
  201. end
  202.  
  203. ----------------------------------------
  204. -- Adds a photo to the end of an existing photoset.
  205. -- @param {string} photoset_id
  206. -- @param {string} photo_id
  207. -- @return {propList}
  208. ----------------------------------------
  209. on photoset_add_photo (me, photoset_id, photo_id)
  210.     param_obj = [:]
  211.     param_obj["format"] = "json"
  212.     param_obj["nojsoncallback"] = "1"
  213.     param_obj["method"] = "flickr.photosets.addPhoto"
  214.     param_obj["photoset_id"] = photoset_id
  215.     param_obj["photo_id"] = photo_id
  216.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  217.     if integerP(res) then
  218.         return ["stat": "fail", "curl_error":curl_error(res)]
  219.     else if me._err[1]<200 or me._err[1]>=300 then
  220.         return ["stat": "fail", "code":me._err[1]]
  221.     else
  222.         json = res.readRawString(res.length)
  223.         return $.json.decode(json)
  224.     end if
  225. end
  226.  
  227. ----------------------------------------
  228. -- Removes a photo from a photoset.
  229. -- @param {string} photoset_id
  230. -- @param {string} photo_id
  231. -- @return {propList}
  232. ----------------------------------------
  233. on photoset_remove_photo (me, photoset_id, photo_id)
  234.     param_obj = [:]
  235.     param_obj["format"] = "json"
  236.     param_obj["nojsoncallback"] = "1"
  237.     param_obj["method"] = "flickr.photosets.removePhoto"
  238.     param_obj["photoset_id"] = photoset_id
  239.     param_obj["photo_id"] = photo_id
  240.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  241.     if integerP(res) then
  242.         return ["stat": "fail", "curl_error":curl_error(res)]
  243.     else if me._err[1]<200 or me._err[1]>=300 then
  244.         return ["stat": "fail", "code":me._err[1]]
  245.     else
  246.         json = res.readRawString(res.length)
  247.         return $.json.decode(json)
  248.     end if
  249. end
  250.  
  251. ----------------------------------------
  252. -- Removes multiple photos from a photoset.
  253. -- @param {string} photoset_id
  254. -- @param {list} photo_ids
  255. -- @return {propList}
  256. ----------------------------------------
  257. on photoset_remove_photos (me, photoset_id, photo_ids)
  258.     param_obj = [:]
  259.     param_obj["format"] = "json"
  260.     param_obj["nojsoncallback"] = "1"
  261.     param_obj["method"] = "flickr.photosets.removePhotos"
  262.     param_obj["photoset_id"] = photoset_id
  263.     str = photo_ids[1]
  264.     repeat with i = 2 to photo_ids.count
  265.         put ","&photo_ids[i] after str
  266.     end repeat
  267.     param_obj["photo_ids"] = str
  268.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err, "post")
  269.     if integerP(res) then
  270.         return ["stat": "fail", "curl_error":curl_error(res)]
  271.     else if me._err[1]<200 or me._err[1]>=300 then
  272.         return ["stat": "fail", "code":me._err[1]]
  273.     else
  274.         json = res.readRawString(res.length)
  275.         return $.json.decode(json)
  276.     end if
  277. end
  278.  
  279. ----------------------------------------
  280. -- Modifies the photos in a photoset. Use this method to add, remove and re-order photos.
  281. -- @param {string} photoset_id
  282. -- @param {string} primary_photo_id
  283. -- @param {list} photo_ids
  284. -- @return {propList}
  285. ----------------------------------------
  286. on photoset_edit_photos (me, photoset_id, primary_photo_id, photo_ids)
  287.     param_obj = [:]
  288.     param_obj["format"] = "json"
  289.     param_obj["nojsoncallback"] = "1"
  290.     param_obj["method"] = "flickr.photosets.editPhotos"
  291.     param_obj["photoset_id"] = photoset_id
  292.     param_obj["primary_photo_id"] = primary_photo_id
  293.     str = photo_ids[1]
  294.     repeat with i = 2 to photo_ids.count
  295.         put ","&photo_ids[i] after str
  296.     end repeat
  297.     param_obj["photo_ids"] = str
  298.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err, "post")
  299.     if integerP(res) then
  300.         return ["stat": "fail", "curl_error":curl_error(res)]
  301.     else if me._err[1]<200 or me._err[1]>=300 then
  302.         return ["stat": "fail", "code":me._err[1]]
  303.     else
  304.         json = res.readRawString(res.length)
  305.         return $.json.decode(json)
  306.     end if
  307. end
  308.  
  309. ----------------------------------------
  310. -- Creates a new photoset for the calling user.
  311. -- @param {string} primary_photo_id
  312. -- @param {string} photoset_title
  313. -- @param {string} [photoset_description]
  314. -- @return {propList}
  315. ----------------------------------------
  316. on photoset_create (me, primary_photo_id, photoset_title, photoset_description)
  317.     param_obj = [:]
  318.     param_obj["format"] = "json"
  319.     param_obj["nojsoncallback"] = "1"
  320.     param_obj["method"] = "flickr.photosets.create"
  321.     param_obj["primary_photo_id"] = primary_photo_id
  322.     param_obj["title"] = photoset_title
  323.     if not voidP(photoset_description) then
  324.         param_obj["description"] = photoset_description
  325.     end if
  326.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  327.     if integerP(res) then
  328.         return ["stat": "fail", "curl_error":curl_error(res)]
  329.     else if me._err[1]<200 or me._err[1]>=300 then
  330.         return ["stat": "fail", "code":me._err[1]]
  331.     else
  332.         json = res.readRawString(res.length)
  333.         return $.json.decode(json)
  334.     end if
  335. end
  336.  
  337. ----------------------------------------
  338. -- Deletes a photoset.
  339. -- @param {string} photoset_id
  340. -- @return {propList}
  341. ----------------------------------------
  342. on photoset_delete (me, photoset_id)
  343.     param_obj = [:]
  344.     param_obj["format"] = "json"
  345.     param_obj["nojsoncallback"] = "1"
  346.     param_obj["method"] = "flickr.photosets.delete"
  347.     param_obj["photoset_id"] = photoset_id
  348.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  349.     if integerP(res) then
  350.         return ["stat": "fail", "curl_error":curl_error(res)]
  351.     else if me._err[1]<200 or me._err[1]>=300 then
  352.         return ["stat": "fail", "code":me._err[1]]
  353.     else
  354.         json = res.readRawString(res.length)
  355.         return $.json.decode(json)
  356.     end if
  357. end
  358.  
  359. ----------------------------------------
  360. -- Set photoset primary photo.
  361. -- @param {string} photoset_id
  362. -- @param {string} photo_id
  363. -- @return {propList}
  364. ----------------------------------------
  365. on photoset_set_primary_photo (me, photoset_id, photo_id)
  366.     param_obj = [:]
  367.     param_obj["format"] = "json"
  368.     param_obj["nojsoncallback"] = "1"
  369.     param_obj["method"] = "flickr.photosets.setPrimaryPhoto"
  370.     param_obj["photoset_id"] = photoset_id
  371.     param_obj["photo_id"] = photo_id
  372.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  373.     if integerP(res) then
  374.         return ["stat": "fail", "curl_error":curl_error(res)]
  375.     else if me._err[1]<200 or me._err[1]>=300 then
  376.         return ["stat": "fail", "code":me._err[1]]
  377.     else
  378.         json = res.readRawString(res.length)
  379.         return $.json.decode(json)
  380.     end if
  381. end
  382.  
  383. ----------------------------------------
  384. -- Sets the order of photos for the specified set.
  385. -- @param {string} photoset_id
  386. -- @param {list} photo_ids
  387. -- @return {propList}
  388. ----------------------------------------
  389. on photoset_reorder_photos (me, photoset_id, photo_ids)
  390.     param_obj = [:]
  391.     param_obj["format"] = "json"
  392.     param_obj["nojsoncallback"] = "1"
  393.     param_obj["method"] = "flickr.photosets.reorderPhotos"
  394.     param_obj["photoset_id"] = photoset_id
  395.     str = photo_ids[1]
  396.     repeat with i = 2 to photo_ids.count
  397.         put ","&photo_ids[i] after str
  398.     end repeat
  399.     param_obj["photo_ids"] = str
  400.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err, "post")
  401.     if integerP(res) then
  402.         return ["stat": "fail", "curl_error":curl_error(res)]
  403.     else if me._err[1]<200 or me._err[1]>=300 then
  404.         return ["stat": "fail", "code":me._err[1]]
  405.     else
  406.         json = res.readRawString(res.length)
  407.         return $.json.decode(json)
  408.     end if
  409. end
  410.  
  411. ----------------------------------------
  412. -- Sets the meta information for a photoset.
  413. -- @param {string} photoset_id
  414. -- @param {string} photoset_title
  415. -- @return {propList}
  416. ----------------------------------------
  417. on photoset_set_title (me, photoset_id, photoset_title)
  418.     param_obj = [:]
  419.     param_obj["format"] = "json"
  420.     param_obj["nojsoncallback"] = "1"
  421.     param_obj["method"] = "flickr.photosets.editMeta"
  422.     param_obj["photoset_id"] = photoset_id
  423.     param_obj["title"] = photoset_title
  424.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  425.     if integerP(res) then
  426.         return ["stat": "fail", "curl_error":curl_error(res)]
  427.     else if me._err[1]<200 or me._err[1]>=300 then
  428.         return ["stat": "fail", "code":me._err[1]]
  429.     else
  430.         json = res.readRawString(res.length)
  431.         return $.json.decode(json)
  432.     end if
  433. end
  434.  
  435. ----------------------------------------
  436. -- Sets the meta information for a photoset.
  437. -- @param {string} photoset_id
  438. -- @param {string} photoset_description
  439. -- @return {propList}
  440. ----------------------------------------
  441. on photoset_set_description (me, photoset_id, photoset_description)
  442.     param_obj = [:]
  443.     param_obj["format"] = "json"
  444.     param_obj["nojsoncallback"] = "1"
  445.     param_obj["method"] = "flickr.photosets.editMeta"
  446.     param_obj["photoset_id"] = photoset_id
  447.     param_obj["description"] = photoset_description
  448.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  449.     if integerP(res) then
  450.         return ["stat": "fail", "curl_error":curl_error(res)]
  451.     else if me._err[1]<200 or me._err[1]>=300 then
  452.         return ["stat": "fail", "code":me._err[1]]
  453.     else
  454.         json = res.readRawString(res.length)
  455.         return $.json.decode(json)
  456.     end if
  457. end
  458.  
  459. ----------------------------------------
  460. -- Gets information about a photo. The calling user must have permission to view the photo.
  461. -- @param {string} photo_id
  462. -- @return {propList}
  463. ----------------------------------------
  464. on photo_get_info (me, photo_id)
  465.     param_obj = [:]
  466.     param_obj["format"] = "json"
  467.     param_obj["nojsoncallback"] = "1"
  468.     param_obj["method"] = "flickr.photos.getInfo"
  469.     param_obj["photo_id"] = photo_id
  470.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  471.     if integerP(res) then
  472.         return ["stat": "fail", "curl_error":curl_error(res)]
  473.     else if me._err[1]<200 or me._err[1]>=300 then
  474.         return ["stat": "fail", "code":me._err[1]]
  475.     else
  476.         json = res.readRawString(res.length)
  477.         return $.json.decode(json)
  478.     end if
  479. end
  480.  
  481. ----------------------------------------
  482. -- Retrieves a list of EXIF/TIFF/GPS tags for a given photo. The calling user must have permission to view the photo.
  483. -- @param {string} photo_id
  484. -- @return {propList}
  485. ----------------------------------------
  486. on photo_get_exif (me, photo_id)
  487.     param_obj = [:]
  488.     param_obj["format"] = "json"
  489.     param_obj["nojsoncallback"] = "1"
  490.     param_obj["method"] = "flickr.photos.getExif"
  491.     param_obj["photo_id"] = photo_id
  492.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  493.     if integerP(res) then
  494.         return ["stat": "fail", "curl_error":curl_error(res)]
  495.     else if me._err[1]<200 or me._err[1]>=300 then
  496.         return ["stat": "fail", "code":me._err[1]]
  497.     else
  498.         json = res.readRawString(res.length)
  499.         return $.json.decode(json)
  500.     end if
  501. end
  502.  
  503. ----------------------------------------
  504. -- Returns the available sizes for a photo. The calling user must have permission to view the photo.
  505. -- @param {string} photo_id
  506. -- @return {propList}
  507. ----------------------------------------
  508. on photo_get_sizes (me, photo_id)
  509.     param_obj = [:]
  510.     param_obj["format"] = "json"
  511.     param_obj["nojsoncallback"] = "1"
  512.     param_obj["method"] = "flickr.photos.getSizes"
  513.     param_obj["photo_id"] = photo_id
  514.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  515.     if integerP(res) then
  516.         return ["stat": "fail", "curl_error":curl_error(res)]
  517.     else if me._err[1]<200 or me._err[1]>=300 then
  518.         return ["stat": "fail", "code":me._err[1]]
  519.     else
  520.         json = res.readRawString(res.length)
  521.         return $.json.decode(json)
  522.     end if
  523. end
  524.  
  525. ----------------------------------------
  526. -- Returns URL of photo with specified size (photo label) available sizes for a photo.
  527. -- @param {string} photo_id
  528. -- @param {string} photo_label
  529. -- @return {propList}
  530. ----------------------------------------
  531. on photo_get_url (me, photo_id, photo_label)
  532.     res = me.photo_get_sizes(photo_id)
  533.     if res["stat"]<>"ok" then
  534.         return res
  535.     end if
  536.     repeat with s in res["sizes"]["size"]
  537.         if s["label"] = photo_label then
  538.             res["url"] = s["source"]
  539.             return res
  540.         end if
  541.     end repeat
  542.     return ["stat": "fail"]
  543. end
  544.  
  545. ----------------------------------------
  546. -- Sets the meta information for a photo.
  547. -- @param {string} photo_id
  548. -- @param {string} photo_title
  549. -- @return {propList}
  550. ----------------------------------------
  551. on photo_set_title (me, photo_id, photo_title)
  552.     param_obj = [:]
  553.     param_obj["format"] = "json"
  554.     param_obj["nojsoncallback"] = "1"
  555.     param_obj["method"] = "flickr.photos.setMeta"
  556.     param_obj["photo_id"] = photo_id
  557.     param_obj["title"] = photo_title
  558.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  559.     if integerP(res) then
  560.         return ["stat": "fail", "curl_error":curl_error(res)]
  561.     else if me._err[1]<200 or me._err[1]>=300 then
  562.         return ["stat": "fail", "code":me._err[1]]
  563.     else
  564.         json = res.readRawString(res.length)
  565.         return $.json.decode(json)
  566.     end if
  567. end
  568.  
  569. ----------------------------------------
  570. -- Sets the meta information for a photo.
  571. -- @param {string} photo_id
  572. -- @param {string} photo_description
  573. -- @return {propList}
  574. ----------------------------------------
  575. on photo_set_description (me, photo_id, photo_description)
  576.     param_obj = [:]
  577.     param_obj["format"] = "json"
  578.     param_obj["nojsoncallback"] = "1"
  579.     param_obj["method"] = "flickr.photos.setMeta"
  580.     param_obj["photo_id"] = photo_id
  581.     param_obj["description"] = photo_description
  582.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  583.     if integerP(res) then
  584.         return ["stat": "fail", "curl_error":curl_error(res)]
  585.     else if me._err[1]<200 or me._err[1]>=300 then
  586.         return ["stat": "fail", "code":me._err[1]]
  587.     else
  588.         json = res.readRawString(res.length)
  589.         return $.json.decode(json)
  590.     end if
  591. end
  592.  
  593. ----------------------------------------
  594. -- Adds tags to a photo.
  595. -- @param {string} photo_id
  596. -- @param {string} tags
  597. -- @return {propList}
  598. ----------------------------------------
  599. on photo_add_tags (me, photo_id, tags)
  600.     param_obj = [:]
  601.     param_obj["format"] = "json"
  602.     param_obj["nojsoncallback"] = "1"
  603.     param_obj["method"] = "flickr.photos.addTags"
  604.     param_obj["photo_id"] = photo_id
  605.     param_obj["tags"] = tags
  606.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  607.     if integerP(res) then
  608.         return ["stat": "fail", "curl_error":curl_error(res)]
  609.     else if me._err[1]<200 or me._err[1]>=300 then
  610.         return ["stat": "fail", "code":me._err[1]]
  611.     else
  612.         json = res.readRawString(res.length)
  613.         return $.json.decode(json)
  614.     end if
  615. end
  616.  
  617. ----------------------------------------
  618. -- Removes a tag from a photo.
  619. -- @param {string} photo_id
  620. -- @param {string} tag_id
  621. -- @return {propList}
  622. ----------------------------------------
  623. on photo_remove_tag (me, photo_id, tag_id)
  624.     param_obj = [:]
  625.     param_obj["format"] = "json"
  626.     param_obj["nojsoncallback"] = "1"
  627.     param_obj["method"] = "flickr.photos.removeTag"
  628.     param_obj["photo_id"] = photo_id
  629.     param_obj["tag_id"] = tag_id
  630.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  631.     if integerP(res) then
  632.         return ["stat": "fail", "curl_error":curl_error(res)]
  633.     else if me._err[1]<200 or me._err[1]>=300 then
  634.         return ["stat": "fail", "code":me._err[1]]
  635.     else
  636.         json = res.readRawString(res.length)
  637.         return $.json.decode(json)
  638.     end if
  639. end
  640.  
  641. ----------------------------------------
  642. -- Deletes a photo from flickr.
  643. -- @param {string} photo_id
  644. -- @return {propList}
  645. ----------------------------------------
  646. on photo_delete (me, photo_id)
  647.     param_obj = [:]
  648.     param_obj["format"] = "json"
  649.     param_obj["nojsoncallback"] = "1"
  650.     param_obj["method"] = "flickr.photos.delete"
  651.     param_obj["photo_id"] = photo_id
  652.     res = $.oauth.call_api("https://api.flickr.com/services/rest", param_obj, me._err)
  653.     if integerP(res) then
  654.         return ["stat": "fail", "curl_error":curl_error(res)]
  655.     else if me._err[1]<200 or me._err[1]>=300 then
  656.         return ["stat": "fail", "code":me._err[1]]
  657.     else
  658.         json = res.readRawString(res.length)
  659.         return $.json.decode(json)
  660.     end if
  661. end
  662.  
  663. ----------------------------------------
  664. -- Returns photo of specified flavor (size label) as byteArray.
  665. -- @param {string} photo_id
  666. -- @param {string} photo_label
  667. -- @param {symbol} [progress_callback]
  668. -- @param {object} [progress_target]
  669. -- ASYNC MODE (OPTIONAL):
  670. -- @param {symbol} [result_callback]
  671. -- @param {object} [result_target]
  672. -- @param {propList} [custom_data]
  673. -- @return {bytearray|VOID}
  674. ----------------------------------------
  675. on photo_get_bytes (me, photo_id, photo_label, progress_callback, progress_target, result_callback, result_target, custom_data)
  676.     u = me.photo_get_url(photo_id, photo_label)
  677.     if u["stat"]<>"ok" then
  678.         if symbolP(result_callback) then
  679.             if voidP(result_target) then
  680.                 result_target = _movie
  681.             end if
  682.             call(result_callback, result_target, u)
  683.         else
  684.             return u
  685.         end if
  686.     end if
  687.     ch = $.curl.init()
  688.     if me._verbose then
  689.         ch.setOption($.curl.CURLOPT.VERBOSE, 1)
  690.     end if
  691.     ch.setOption($.curl.CURLOPT.URL, u["url"])
  692.     if symbolP(progress_callback) then
  693.         ch.setOption($.curl.CURLOPT.NOPROGRESS, 0)
  694.         if voidP(progress_target) then
  695.             progress_target = _movie
  696.         end if
  697.         ch.setProgressCallback(progress_callback, progress_target)
  698.     end if
  699.     if symbolP(result_callback) then
  700.         -- ASYNC
  701.         if voidP(custom_data) then
  702.             custom_data = [:]
  703.         end if
  704.         custom_data[#result_callback] = result_callback
  705.         if voidP(result_target) then
  706.             result_target = _movie
  707.         end if
  708.         custom_data[#result_target] = result_target
  709.         custom_data[#url] = u["url"]
  710.         $.curl.execAsyncDetached(ch, #_photo_get_bytes_received, me, 1, custom_data)
  711.     else
  712.         -- SYNC
  713.         res = ch.exec(1)
  714.         if integerP(res) then
  715.             return ["stat": "fail", "curl_error":curl_error(res)]
  716.         end if
  717.         response_code = integer(ch.getInfo($.curl.CURLINFO.RESPONSE_CODE))
  718.         if response_code<200 or response_code>=300 then
  719.             return ["stat": "fail", "code":response_code]
  720.         end if
  721.         return ["stat":"ok", "url":u["url"], "data":res]
  722.     end if
  723. end
  724.  
  725. ----------------------------------------
  726. -- @callback
  727. ----------------------------------------
  728. on _photo_get_bytes_received (me, res, ch, custom_data)
  729.     if integerP(res) then
  730.         return call(custom_data.result_callback, custom_data.result_target, ["stat": "fail", "curl_error":curl_error(res)])
  731.     end if
  732.     response_code = integer(ch.getInfo($.curl.CURLINFO.RESPONSE_CODE))
  733.     if response_code<200 or response_code>=300 then
  734.         return call(custom_data.result_callback, custom_data.result_target, ["stat": "fail", "code":response_code])
  735.     end if
  736.     call(custom_data.result_callback, custom_data.result_target, ["stat":"ok", "url":custom_data.url, "data":res])
  737. end
  738.  
  739. ----------------------------------------
  740. -- Downloads a photo of specified flavor (size label).
  741. -- @param {string} photo_id
  742. -- @param {string} photo_label
  743. -- @param {string} target_file
  744. -- @param {symbol} [progress_callback]
  745. -- @param {object} [progress_target]
  746. -- ASYNC MODE (OPTIONAL):
  747. -- @param {symbol} [result_callback]
  748. -- @param {object} [result_target]
  749. -- @param {propList} [custom_data]
  750. -- @return {bytearray|VOID}
  751. ----------------------------------------
  752. on photo_download (me, photo_id, photo_label, target_file, progress_callback, progress_target, result_callback, result_target, custom_data)
  753.     u = me.photo_get_url(photo_id, photo_label)
  754.     if u["stat"]<>"ok" then
  755.         if symbolP(result_callback) then
  756.             if voidP(result_target) then
  757.                 result_target = _movie
  758.             end if
  759.             call(result_callback, result_target, u)
  760.         else
  761.             return u
  762.         end if
  763.     end if
  764.     ch = $.curl.init()
  765.     if me._verbose then
  766.         ch.setOption($.curl.CURLOPT.VERBOSE, 1)
  767.     end if
  768.     ch.setOption($.curl.CURLOPT.URL, u["url"])
  769.     ch.setDestinationFile(target_file)
  770.     if symbolP(progress_callback) then
  771.         ch.setOption($.curl.CURLOPT.NOPROGRESS, 0)
  772.         if voidP(progress_target) then
  773.             progress_target = _movie
  774.         end if
  775.         ch.setProgressCallback(progress_callback, progress_target)
  776.     end if
  777.     if symbolP(result_callback) then
  778.         -- ASYNC
  779.         if voidP(custom_data) then
  780.             custom_data = [:]
  781.         end if
  782.         custom_data[#result_callback] = result_callback
  783.         if voidP(result_target) then
  784.             result_target = _movie
  785.             end if
  786.         custom_data[#result_target] = result_target
  787.         custom_data[#target_file] = target_file
  788.         custom_data[#url] = u["url"]
  789.         $.curl.execAsyncDetached(ch, #_photo_download_received, me, 0, custom_data)
  790.     else
  791.         -- SYNC
  792.         res = ch.exec(0)
  793.         if res<>0 then
  794.             $.file.delete(target_file)
  795.             return ["stat": "fail", "curl_error":curl_error(res)]
  796.         end if
  797.         response_code = integer(ch.getInfo($.curl.CURLINFO.RESPONSE_CODE))
  798.         if response_code<200 or response_code>=300 then
  799.             $.file.delete(target_file)
  800.             return ["stat": "fail", "code":response_code]
  801.         end if
  802.         return ["stat":"ok", "url":u["url"]]
  803.     end if
  804. end
  805.  
  806. ----------------------------------------
  807. -- @callback
  808. ----------------------------------------
  809. on _photo_download_received (me, res, ch, custom_data)
  810.     if res<>0 then
  811.         $.file.delete(custom_data.target_file)
  812.         return call(custom_data.result_callback, custom_data.result_target, ["stat": "fail", "curl_error":curl_error(res)])
  813.     end if
  814.     response_code = integer(ch.getInfo($.curl.CURLINFO.RESPONSE_CODE))
  815.     if response_code<200 or response_code>=300 then
  816.         $.file.delete(custom_data.target_file)
  817.         return call(custom_data.result_callback, custom_data.result_target, ["stat": "fail", "code":response_code])
  818.     end if
  819.     call(custom_data.result_callback, custom_data.result_target, ["stat":"ok", "url":custom_data.url, "file":custom_data.target_file], ch, custom_data)
  820. end
  821.  
  822. ----------------------------------------
  823. -- Downloads original photo - which can be either JPG, PNG or GIF - to target folder.
  824. -- @param {string} photo_id
  825. -- @param {string} photo_label
  826. -- @param {string} target_folder
  827. -- @param {symbol} [progress_callback]
  828. -- @param {object} [progress_target]
  829. -- ASYNC MODE (OPTIONAL):
  830. -- @param {symbol} [result_callback]
  831. -- @param {object} [result_target]
  832. -- @param {propList} [custom_data]
  833. -- @return {bytearray|VOID}
  834. ----------------------------------------
  835. on photo_download_original (me, photo_id, target_folder, progress_callback, progress_target, result_callback, result_target, custom_data)
  836.     u = me.photo_get_url(photo_id, "Original")
  837.     if u["stat"]<>"ok" then
  838.         if symbolP(result_callback) then
  839.             if voidP(result_target) then
  840.                 result_target = _movie
  841.             end if
  842.             call(result_callback, result_target, u)
  843.         else
  844.             return u
  845.         end if
  846.     end if
  847.  
  848.     od = _player.itemDelimiter
  849.     _player.itemDelimiter = "."
  850.     file_type = the last item of u["url"]
  851.     _player.itemDelimiter = od
  852.     target_file = target_folder & "\" & photo_id & "." & file_type
  853.  
  854.     ch = $.curl.init()
  855.     if me._verbose then
  856.         ch.setOption($.curl.CURLOPT.VERBOSE, 1)
  857.     end if
  858.     ch.setOption($.curl.CURLOPT.URL, u["url"])
  859.     ch.setDestinationFile(target_file)
  860.     if symbolP(progress_callback) then
  861.         ch.setOption($.curl.CURLOPT.NOPROGRESS, 0)
  862.         if voidP(progress_target) then
  863.             progress_target = _movie
  864.         end if
  865.         ch.setProgressCallback(progress_callback, progress_target)
  866.     end if
  867.     if symbolP(result_callback) then
  868.         -- ASYNC
  869.         if voidP(custom_data) then
  870.             custom_data = [:]
  871.         end if
  872.         custom_data[#result_callback] = result_callback
  873.         if voidP(result_target) then
  874.             result_target = _movie
  875.         end if
  876.         custom_data[#result_target] = result_target
  877.         custom_data[#target_file] = target_file
  878.         custom_data[#url] = u["url"]
  879.         $.curl.execAsyncDetached(ch, #_photo_download_received, me, 0, custom_data)
  880.     else
  881.         -- SYNC
  882.         res = ch.exec(0)
  883.         if res<>0 then
  884.             $.file.delete(target_file)
  885.             return ["stat": "fail", "curl_error":curl_error(res)]
  886.         end if
  887.         response_code = integer(ch.getInfo($.curl.CURLINFO.RESPONSE_CODE))
  888.         if response_code<200 or response_code>=300 then
  889.             $.file.delete(target_file)
  890.             return ["stat": "fail", "code":response_code]
  891.         end if
  892.         return ["stat":"ok", "url":u["url"], "file":target_file]
  893.     end if
  894. end
  895.  
  896. ----------------------------------------
  897. -- Uploads a photo to specified photo set.
  898. -- @param {string} photoset_id - EMPTY for no set
  899. -- @param {string} photo_file
  900. -- @param {symbol} [progress_callback]
  901. -- @param {object} [progress_target]
  902. -- ASYNC MODE (OPTIONAL):
  903. -- @param {symbol} [result_callback]
  904. -- @param {object} [result_target]
  905. -- @param {propList} [custom_data]
  906. -- @return {propList|VOID}
  907. ----------------------------------------
  908. on photo_upload (me, photoset_id, photo_file, progress_callback, progress_target, result_callback, result_target, custom_data)
  909.     param_obj = [:]
  910.     param_obj["format"] = "json"
  911.     param_obj["nojsoncallback"] = "1"
  912.     base_url = "https://up.flickr.com/services/upload/"
  913.     sig = $.oauth.get_signature(base_url, $.oauth.build_query(param_obj), "post")
  914.  
  915.     ch = $.curl.init()
  916.     if me._verbose then
  917.         ch.setOption($.curl.CURLOPT.VERBOSE, 1)
  918.     end if
  919.     ch.setOption($.curl.CURLOPT.URL, base_url)
  920.     ch.setOption($.curl.CURLOPT.SSL_VERIFYPEER, 0)
  921.  
  922.     -- create a form list
  923.     form = []
  924.     cnt = param_obj.count
  925.     repeat with i = 1 to cnt
  926.         section = [:]
  927.         section.addProp($.curl.CURLFORM.COPYNAME, param_obj.getPropAt(i))
  928.         section.addProp($.curl.CURLFORM.COPYCONTENTS, string(param_obj[i]))
  929.         form.add(section)
  930.     end repeat
  931.     section = [:]
  932.     section.addProp($.curl.CURLFORM.COPYNAME, "oauth_signature")
  933.     section.addProp($.curl.CURLFORM.COPYCONTENTS, sig)
  934.     form.add(section)
  935.     section = [:]
  936.     section.addProp($.curl.CURLFORM.COPYNAME, "photo")
  937.     section.addProp($.curl.CURLFORM.FILE, photo_file)
  938.     form.add(section)
  939.     ch.setOption($.curl.CURLOPT.POST, 1)
  940.     ch.setForm(form)
  941.  
  942.     if symbolP(progress_callback) then
  943.         ch.setOption($.curl.CURLOPT.NOPROGRESS, 0)
  944.         if voidP(progress_target) then
  945.             progress_target = _movie
  946.         end if
  947.         ch.setProgressCallback(progress_callback, progress_target)
  948.     end if
  949.  
  950.     if symbolP(result_callback) then
  951.         -- ASYNC
  952.         if voidP(custom_data) then
  953.             custom_data = [:]
  954.         end if
  955.         custom_data[#photoset_id] = photoset_id
  956.         custom_data[#result_callback] = result_callback
  957.         if voidP(result_target) then
  958.             result_target = _movie
  959.         end if
  960.         custom_data[#result_target] = result_target
  961.         $.curl.execAsyncDetached(ch, #_photo_upload_received, me, 1, custom_data)
  962.     else
  963.         -- SYNC
  964.         res = ch.exec(1)
  965.         if integerP(res) then
  966.             return ["stat": "fail", "curl_error":curl_error(res)]
  967.         end if
  968.         response_code = integer(ch.getInfo($.curl.CURLINFO.RESPONSE_CODE))
  969.         if response_code<200 or response_code>=300 then
  970.             return ["stat": "fail", "code":response_code]
  971.         end if
  972.         res = res.readRawString(res.length)
  973.         $.xmlparser.parseString(res)
  974.         err = $.xmlparser.getError()
  975.         if not voidP(err) then
  976.             return ["stat": "fail", "xml_error":err]
  977.         end if
  978.         res = $.xmlparser.makeSimplePropList($.xmlparser.makePropList(), TRUE)
  979.         stat = res[#rsp][#__attributes][#stat]
  980.         if stat<>"ok" then
  981.             return ["stat": "fail"]
  982.         end if
  983.         if photoset_id<>EMPTY then
  984.             return me.photoset_add_photo(photoset_id, res[#rsp][#photoid])
  985.         else
  986.             return ["stat": "ok"]
  987.         end if
  988.     end if
  989. end
  990.  
  991. ----------------------------------------
  992. -- @callback
  993. ----------------------------------------
  994. on _photo_upload_received (me, res, ch, custom_data)
  995.     if integerP(res) then
  996.         return call(custom_data.result_callback, custom_data.result_target, ["stat": "fail", "curl_error":curl_error(res)])
  997.     end if
  998.     response_code = integer(ch.getInfo($.curl.CURLINFO.RESPONSE_CODE))
  999.     if response_code<200 or response_code>=300 then
  1000.         return call(custom_data.result_callback, custom_data.result_target, ["stat": "fail", "code":response_code])
  1001.     end if
  1002.     res = res.readRawString(res.length)
  1003.     $.xmlparser.parseString(res)
  1004.     err = $.xmlparser.getError()
  1005.     if not voidP(err) then
  1006.         call(custom_data.result_callback, custom_data.result_target, ["stat": "fail", "xml_error":err])
  1007.     end if
  1008.     res = $.xmlparser.makeSimplePropList($.xmlparser.makePropList(), TRUE)
  1009.     stat = res[#rsp][#__attributes][#stat]
  1010.     if stat<>"ok" then
  1011.         return call(custom_data.result_callback, custom_data.result_target, ["stat": "fail"])
  1012.     end if
  1013.     if custom_data.photoset_id<>EMPTY then
  1014.         res = me.photoset_add_photo(custom_data.photoset_id, res[#rsp][#photoid])
  1015.         call(custom_data.result_callback, custom_data.result_target, res)
  1016.     else
  1017.         call(custom_data.result_callback, custom_data.result_target, ["stat": "ok"])
  1018.     end if
  1019. end
  1020.  
[raw code]