@ca-plant-list/ca-plant-list 0.4.31 → 0.4.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/data/synonyms.csv CHANGED
@@ -686,6 +686,7 @@ Erigeron peregrinus var. callianthemus,Erigeron glacialis var. glacialis
686
686
  Eriocoma lemmonii subsp. lemmonii,Stipa lemmonii var. lemmonii,INAT
687
687
  Eriogonella membranacea,Chorizanthe membranacea
688
688
  Eriogonum acetoselloides,Eriogonum gracile var. gracile
689
+ Eriogonum arachnoideum,Eriogonum latifolium
689
690
  Eriogonum auriculatum,Eriogonum nudum var. auriculatum
690
691
  Eriogonum caninum,Eriogonum luteolum var. caninum
691
692
  Eriogonum curvatum,Eriogonum wrightii var. subscaposum
@@ -706,6 +707,7 @@ Eriogonum lobbii var. minus,Eriogonum lobbii
706
707
  Eriogonum marifolium var. incanum,Eriogonum incanum
707
708
  Eriogonum nivale,Eriogonum ovalifolium var. nivale
708
709
  Eriogonum nudum subsp. pauciflorum,Eriogonum nudum var. pauciflorum
710
+ Eriogonum oblongifolium,Eriogonum latifolium
709
711
  Eriogonum polifolium,Eriogonum fasciculatum var. polifolium
710
712
  Eriogonum polyanthum var. bahiiforme,Eriogonum umbellatum var. bahiiforme
711
713
  Eriogonum revolutum,Eriogonum fasciculatum var. polifolium
package/data/taxa.csv CHANGED
@@ -237,7 +237,7 @@ Brickellia californica,California brickelbush,N,1794,1152,58803,202493,true,Bric
237
237
  Briza maxima,quaking grass,X,16135,1165,57157,136989,true
238
238
  Briza minor,little quaking grass,X,16137,1166,57162,136993,true
239
239
  Brodiaea elegans subsp. elegans,harvest brodiaea,N,49461,1175,57127,202520,true,Harvest Brodiaea,corm,purple,4,8
240
- Brodiaea terrestris subsp. terrestris,,N,49464,1188,59081,202533,true,Dwarf Brodiaea,corm
240
+ Brodiaea terrestris subsp. terrestris,,N,49464,1188,59081,202533,true,Dwarf Brodiaea,corm,purple,4,7
241
241
  Bromus arenarius,Australian chess,X,16216,1191,58368,137101,true
242
242
  Bromus berteroanus,Chilean chess,X,16219,9740,75897,137110,true
243
243
  Bromus catharticus var. catharticus,rescue grass,X,85279,11433,80494,169088,true
@@ -275,9 +275,9 @@ Callitriche marginata,water-starwort,N,16692,1259,58093,64128,true,Winged Water
275
275
  Callitriche trochlearis,,N,16702,1261,69994,64137,true,Effluent Water-starwort
276
276
  Calochortus albus,white globe lily,N,16710,1264,51315,202570,true,White Globe Lily,,white,4,6
277
277
  Calochortus argillosus,clay mariposa lily,N,76542,1268,64330,202576,true,Clay Mariposa Lily,bulb,"white,pink",4,6
278
- Calochortus clavatus var. pallidus,bulb,N,55455,1275,58360,202583,true,Pale Yellow Mariposa
279
- Calochortus invenustus,bulb,N,16733,1284,64432,202590,true,Plain Mariposa Lily
280
- Calochortus leichtlinii,bulb,N,16735,1288,52542,202594,true,Leichtlin's Mariposa Lily
278
+ Calochortus clavatus var. pallidus,,N,55455,1275,58360,202583,true,Pale Yellow Mariposa
279
+ Calochortus invenustus,,N,16733,1284,64432,202590,true,Plain Mariposa Lily
280
+ Calochortus leichtlinii,,N,16735,1288,52542,202594,true,Leichtlin's Mariposa Lily
281
281
  Calochortus luteus,yellow mariposa lily,N,16737,1290,51077,202595,true,Yellow Mariposa Lily,bulb,yellow,4,6
282
282
  Calochortus pulchellus,Mt. Diablo fairy lantern,N,16755,1303,47326,202609,true,Mt. Diablo Fairy Lantern,bulb,,,,50,1B.2,,,S2,G2
283
283
  Calochortus splendens,,N,16759,1306,58361,202611,true,Splendid Mariposa Lily,bulb
@@ -364,7 +364,7 @@ Ceanothus thyrsiflorus,blue blossom,N,18501,1830,56617,12790,true,Blueblossom Ce
364
364
  Centaurea calcitrapa,purple star-thistle,X,1922,1845,56865,202776,true
365
365
  Centaurea cyanus,"bachelor's button,cornflower",X,1925,1846,933404,202778,true
366
366
  Centaurea iberica,Iberian starthistle,X,1931,1849,76212,206620,true
367
- Centaurea melitensis,"tocalote,Maltese start-thistle",X,1934,1851,57922,202785,true
367
+ Centaurea melitensis,"tocalote,Maltese star-thistle",X,1934,1851,57922,202785,true
368
368
  Centaurea solstitialis,yellow star-thistle,X,1946,1853,52588,202793,true
369
369
  Centranthus ruber,red valerian,X,18595,1864,57283,202799
370
370
  Centromadia fitchii,Fitch's spikeweed,N,77593,10809,58804,202801,true,Fitch Spikeweed
@@ -443,7 +443,7 @@ Claytonia exigua subsp. glauca,,N,76949,2233,57229,127855,true,Serpentine Spring
443
443
  Claytonia gypsophiloides,candy stripers,N,19620,2234,55344,112597,true,Gypsum Springbeauty,annual,pink,3,5
444
444
  Claytonia parviflora subsp. parviflora,,N,74695,2242,58296,127861,true,Utah Miner's Lettuce,"annual,perennial",white,3,6
445
445
  Claytonia perfoliata subsp. mexicana,,N,76956,2245,53004,127866,true,Southern Miner's Lettuce,annual,white,2,4
446
- Claytonia perfoliata subsp. perfoliata,Miner's lettuce,N,49921,2246,53002,127867,true,Miner's Lettuce,annual,white,1,5
446
+ Claytonia perfoliata subsp. perfoliata,miner's lettuce,N,49921,2246,53002,127867,true,Miner's Lettuce,annual,white,1,5
447
447
  Claytonia rubra subsp. depressa,red stem spring beauty,N,76957,2248,79751,127869,true,Miner's Lettuce,annual,white,2,4
448
448
  Clematis lasiantha,pipestems,N,19682,2254,49876,13749,true,Chaparral Clematis,,white,1,6
449
449
  Clematis ligusticifolia,virgin's bower,N,19683,2255,58996,13750,true,Virgin's Bower,,white,6,9
@@ -701,6 +701,7 @@ Eriogonum fasciculatum var. polifolium,,N,58546,3247,58272,129983,true,Interior
701
701
  Eriogonum gracile var. gracile,slender buckwheat,N,58563,3257,58982,129999,true,Slender Woolly Wild Buckwheat
702
702
  Eriogonum incanum,frosted buckwheat,N,24809,3279,62680,114044,true,Frosted Wild Buckwheat,perennial,yellow,6,9
703
703
  Eriogonum inerme var. inerme,unarmed buckwheat,N,58586,9110,80799,130026,true,Unarmed Wild Buckwheat
704
+ Eriogonum latifolium,seaside wild buckwheat,N,24832,3293,57211,114060,true,Coast Buckwheat,perennial,"white,pink",1,12
704
705
  Eriogonum lobbii,granite buckwheat,N,24839,9935,77005,114067,true,Lobb's Buckwheat,perennial,"white,pink",6,8
705
706
  Eriogonum luteolum var. caninum,Tiburon buckwheat,N,58623,3297,61205,130067,true,Tiburon Buckwheat,,,,,733,1B.2,,,S2,G5T2
706
707
  Eriogonum luteolum var. luteolum,,N,58624,3298,64226,130068,true,Golden-carpet Wild Buckwheat
@@ -1089,10 +1090,10 @@ Logfia gallica,,X,31363,9521,56949,204736,true,,annual,"brown,yellow",3,7
1089
1090
  Lomatium californicum,chu-chu-pate,N,31389,4950,56824,204737,,California Lomatium,,yellow,4,6
1090
1091
  Lomatium caruifolium var. caruifolium,,N,61026,4953,64328,204739,,Alkali Desertparsley
1091
1092
  Lomatium caruifolium var. denticulatum,,N,61027,4954,60123,204740
1092
- Lomatium dasycarpum subsp. dasycarpum,,N,51334,4960,56829,204743,,Woolly Fruited Lomatium,,white,3,6
1093
- Lomatium macrocarpum,,N,31433,4974,56826,204754,,Bigseed Biscuitroot
1093
+ Lomatium dasycarpum subsp. dasycarpum,,N,51334,4960,56829,204743,,Woolly Fruited Lomatium,perennial,white,3,6
1094
+ Lomatium macrocarpum,,N,31433,4974,56826,204754,,Bigseed Biscuitroot,perennial,white,4,6
1094
1095
  Lomatium nudicaule,,N,31441,4983,77818,204759,,Barestem Biscuitroot
1095
- Lomatium utriculatum,,N,31473,4999,56827,204766,,Common Lomatium,,yellow,2,5
1096
+ Lomatium utriculatum,,N,31473,4999,56827,204766,,Common Lomatium,perennial,yellow,2,5
1096
1097
  Lonicera hispidula,California honeysuckle,N,31505,10075,53416,204768,,Pink Honeysuckle,,pink,5,6
1097
1098
  Lonicera interrupta,chaparral honeysuckle,N,31506,5009,60878,204770,,Chaparral Honeysuckle,,"yellow,white",4,5
1098
1099
  Lonicera involucrata var. ledebourii,black twinberry,N,61081,5012,60990,204773,,Twinberry Honeysuckle
@@ -1196,8 +1197,8 @@ Mercurialis annua,annual mercury,X,33300,5450,68838,25939,true
1196
1197
  Mesembryanthemum nodiflorum,,X,33363,5461,71191,116177,true
1197
1198
  Micranthes californica,,N,91942,11841,78023,26022,true,California Saxifrage
1198
1199
  Micropus amphibolus,,N,33474,5462,78034,204946,true,Mount Diablo Cottonseed,,,,,1507,3.2,,,S3S4,G3G4
1199
- Micropus californicus var. californicus,slender cottonweed,N,7993,5464,58030,204950,true,Cottontop
1200
- Micropus californicus var. subvestitus,,N,7994,5465,81107,207081,true,Q-tips
1200
+ Micropus californicus var. californicus,slender cottonweed,N,7993,5464,58030,204950,true,Cottontop,annual,white,3,6
1201
+ Micropus californicus var. subvestitus,Q-tips,N,7994,5465,81107,207081,true,Q-tips,annual,white,4,6
1201
1202
  Microseris acuminata,,N,4146,5466,60142,204953,true,Sierra Foothill Silverpuffs
1202
1203
  Microseris bigelovii,,N,4147,5467,60977,204954,true,Coastal Silverpuffs
1203
1204
  Microseris campestris,,N,4149,5469,58031,204955,true,San Joaquin Silverpuffs
@@ -1833,8 +1834,8 @@ Triphysaria eriantha subsp. eriantha,butter-and-eggs,N,53279,8129,59332,96567,tr
1833
1834
  Triphysaria pusilla,,N,47296,8133,57276,78297,true,Dwarf Owl's-clover
1834
1835
  Triphysaria versicolor subsp. faucibarbata,,N,53281,8135,60737,206269,true,Triphysaria
1835
1836
  Trisetum canescens,,N,47326,8139,1538928,150155,true,Tall False Oat
1836
- Triteleia hyacinthina,white brodiaea,N,47356,8154,57132,206275,true,White Brodiaea
1837
- Triteleia laxa,Ithuriel's spear,N,47359,8160,51085,206281,true,Ithuriel's Spear
1837
+ Triteleia hyacinthina,white brodiaea,N,47356,8154,57132,206275,true,White Brodiaea,corm,white,3,7
1838
+ Triteleia laxa,Ithuriel's spear,N,47359,8160,51085,206281,true,Ithuriel's Spear,corm,blue,3,6
1838
1839
  Triteleia peduncularis,,N,47363,8164,57133,206284,true,Long Rayed Brodiaea
1839
1840
  Tropaeolum majus,garden nasturtium,X,47408,8167,54329,34321,true
1840
1841
  Tropidocarpum capparideum,caper-fruited tropidocarpum,N,47411,8168,79456,34327,true,Caper-fruited Tropidocarpum,annual,yellow,3,4,1255,1B.1,,,S1,G1
@@ -0,0 +1 @@
1
+ Base of flower funnel-shaped.
@@ -0,0 +1 @@
1
+ Base of flower bell-shaped.
package/lib/photo.js CHANGED
@@ -10,10 +10,10 @@ export class Photo {
10
10
  #rights;
11
11
 
12
12
  /**
13
- * @param {number} id
13
+ * @param {string} id
14
14
  * @param {string} ext
15
- * @param {import("./utils/inat-tools.js").InatLicenseCode} licenseCode
16
- * @param {string} rightsHolder
15
+ * @param {import("./utils/inat-tools.js").AllowedLicenseCode} licenseCode
16
+ * @param {string|undefined} rightsHolder
17
17
  */
18
18
  constructor(id, ext, licenseCode, rightsHolder) {
19
19
  this.#id = id;
@@ -22,7 +22,9 @@ export class Photo {
22
22
  if (licenseCode === "cc0") this.#rights = "CC0";
23
23
  else if (licenseCode === "cc-by") this.#rights = "CC BY";
24
24
  else if (licenseCode === "cc-by-nc") this.#rights = "CC BY-NC";
25
- else this.#rights = "C";
25
+ else {
26
+ throw new Error(`unexpected license code ${licenseCode}`);
27
+ }
26
28
  }
27
29
 
28
30
  /**
@@ -115,27 +115,7 @@ class Taxa {
115
115
  #loadPhotosFromFile(dataDir, filename) {
116
116
  if (!fs.existsSync(path.join(dataDir, filename))) return;
117
117
  /** @type {import("../utils/inat-tools.js").InatCsvPhoto[]} */
118
- const csvPhotos = CSV.parseFile(dataDir, filename).map((row) => {
119
- /** @type {import("../utils/inat-tools.js").InatLicenseCode} */
120
- let licenseCode = "cc-by";
121
- if (row.licenseCode === "cc-by-nc-sa") licenseCode = "cc-by-nc-sa";
122
- else if (row.licenseCode === "cc-by-nc") licenseCode = "cc-by-nc";
123
- else if (row.licenseCode === "cc-by-nc-nd")
124
- licenseCode = "cc-by-nc-nd";
125
- else if (row.licenseCode === "cc-by") licenseCode = "cc-by";
126
- else if (row.licenseCode === "cc-by-sa") licenseCode = "cc-by-sa";
127
- else if (row.licenseCode === "cc-by-nd") licenseCode = "cc-by-nd";
128
- else if (row.licenseCode === "pd") licenseCode = "pd";
129
- else if (row.licenseCode === "gdfl") licenseCode = "gdfl";
130
- else if (row.licenseCode === "cc0") licenseCode = "cc0";
131
- return {
132
- attrName: row.attrName,
133
- ext: row.ext,
134
- id: Number(row.id),
135
- licenseCode,
136
- name: row.name,
137
- };
138
- });
118
+ const csvPhotos = CSV.readFile(path.join(dataDir, filename));
139
119
  for (const csvPhoto of csvPhotos) {
140
120
  const taxon = this.getTaxon(csvPhoto.name);
141
121
  if (!taxon) {
@@ -156,8 +136,9 @@ class Taxa {
156
136
  * @param {string} dataDir
157
137
  */
158
138
  #loadInatPhotos(dataDir) {
159
- this.#loadPhotosFromFile("./data", "inatphotos.csv");
139
+ // Prefer taxon photos, as they are somewhat curated.
160
140
  this.#loadPhotosFromFile(dataDir, "inattaxonphotos.csv");
141
+ this.#loadPhotosFromFile("./data", "inatobsphotos.csv");
161
142
  this.#loadPhotosFromFile(dataDir, "inatobsphotos.csv");
162
143
  }
163
144
 
@@ -2,25 +2,25 @@ import { ProgressMeter } from "../progressmeter.js";
2
2
  import { chunk, sleep } from "../util.js";
3
3
 
4
4
  /**
5
- @typedef {"cc-by-nc-sa"
6
- | "cc-by-nc"
7
- | "cc-by-nc-nd"
8
- | "cc-by"
9
- | "cc-by-sa"
10
- | "cc-by-nd"
11
- | "pd"
12
- | "gdfl"
13
- | "cc0"} InatLicenseCode
5
+ * @typedef {"cc0" | "cc-by" | "cc-by-nc"} AllowedLicenseCode
6
+ * @typedef {{place_id?:string,project_id?:string}} ObsPhotoLocationOptions
7
+ @typedef {{
8
+ id:number,
9
+ observation_photos: {
10
+ photo: import("./inat-tools.js").InatApiPhoto;
11
+ }[];
12
+ }} InatApiObservationPhotos
14
13
  @typedef {{
15
14
  id: string;
15
+ obsId?:string;
16
16
  ext: string;
17
- licenseCode: string;
17
+ licenseCode: AllowedLicenseCode;
18
18
  attrName: string | undefined;
19
19
  }} InatPhotoInfo
20
20
  @typedef {{
21
21
  id: number;
22
22
  attribution: string;
23
- license_code: InatLicenseCode;
23
+ license_code: string;
24
24
  medium_url?: string;
25
25
  url?: string;
26
26
  }} InatApiPhoto
@@ -30,15 +30,38 @@ import { chunk, sleep } from "../util.js";
30
30
  photo: InatApiPhoto;
31
31
  }[];
32
32
  }} InatApiTaxon
33
- @typedef {{
34
- name: string;
35
- id: number;
36
- ext: string;
37
- licenseCode: InatLicenseCode;
38
- attrName: string;
39
- }} InatCsvPhoto
33
+ @typedef {{name: string;} & InatPhotoInfo} InatCsvPhoto
40
34
  */
35
+
41
36
  const ALLOWED_LICENSE_CODES = ["cc0", "cc-by", "cc-by-nc"];
37
+ const FIELDS_OBS_PHOTO =
38
+ "(id:!t,observation_photos:(photo:(url:!t,attribution:!t,license_code:!t)))";
39
+
40
+ /**
41
+ * @param {InatApiPhoto} apiPhoto
42
+ * @returns {InatPhotoInfo|undefined}
43
+ */
44
+ export function convertToCSVPhoto(apiPhoto) {
45
+ const licenseCode = getAllowedLicenseCode(apiPhoto.license_code);
46
+ if (licenseCode === undefined) {
47
+ return;
48
+ }
49
+ const url = apiPhoto.medium_url || apiPhoto.url;
50
+ if (!url) {
51
+ return;
52
+ }
53
+ const ext = url.split(".").at(-1);
54
+ if (!ext) {
55
+ return;
56
+ }
57
+ /** @type {InatPhotoInfo} */
58
+ return {
59
+ id: apiPhoto.id.toString(),
60
+ ext: ext,
61
+ licenseCode: licenseCode,
62
+ attrName: getAttribution(apiPhoto.attribution),
63
+ };
64
+ }
42
65
 
43
66
  /**
44
67
  * @param {string[]} inatTaxonIDs
@@ -55,6 +78,122 @@ async function fetchInatTaxa(inatTaxonIDs) {
55
78
  return json.results;
56
79
  }
57
80
 
81
+ /**
82
+ * @param {import("../types.js").Taxon} taxon
83
+ * @param {{place_id?:string,project_id?:string}} locationOptions
84
+ * @return {Promise<InatApiObservationPhotos[]|Error>}
85
+ */
86
+ async function fetchObservationsForTaxon(
87
+ taxon,
88
+ locationOptions = { place_id: "14" },
89
+ ) {
90
+ const inatTaxonId = taxon.getINatID();
91
+ if (!inatTaxonId) return [];
92
+ let url = new URL(
93
+ `https://api.inaturalist.org/v2/observations/?taxon_id=${inatTaxonId}` +
94
+ "&photo_license=" +
95
+ ALLOWED_LICENSE_CODES.join(",") +
96
+ "&order=desc" +
97
+ "&order_by=votes" +
98
+ "&per_page=5",
99
+ );
100
+ url.searchParams.set("fields", FIELDS_OBS_PHOTO);
101
+ if (locationOptions.place_id) {
102
+ url.searchParams.set("place_id", locationOptions.place_id);
103
+ }
104
+ if (locationOptions.project_id) {
105
+ url.searchParams.set("project_id", locationOptions.project_id);
106
+ }
107
+ const resp = await getResponse(url);
108
+ if (resp instanceof Error) {
109
+ return resp;
110
+ }
111
+
112
+ if (!resp.ok) {
113
+ return new Error(await resp.text());
114
+ }
115
+ const json = await resp.json();
116
+ return json.results;
117
+ }
118
+
119
+ /**
120
+ * @param {string[]} obsIds
121
+ * @returns {Promise<InatApiObservationPhotos[]|Error>}
122
+ */
123
+ export async function getObsPhotosForIds(obsIds) {
124
+ let url = new URL("https://api.inaturalist.org/v2/observations/");
125
+ url.searchParams.set("fields", FIELDS_OBS_PHOTO);
126
+ url.searchParams.set("id", obsIds.join(","));
127
+ url.searchParams.set("per_page", obsIds.length.toString());
128
+
129
+ const resp = await getResponse(url);
130
+ if (resp instanceof Error) {
131
+ return resp;
132
+ }
133
+
134
+ if (!resp.ok) {
135
+ return new Error(await resp.text());
136
+ }
137
+ const json = await resp.json();
138
+ return json.results;
139
+ }
140
+
141
+ /**
142
+ * @param {import("../types.js").Taxon[]} taxaToUpdate
143
+ * @param {ObsPhotoLocationOptions|undefined} locationOptions
144
+ * @returns {Promise<Map<string,InatPhotoInfo[]>>}
145
+ */
146
+ export async function getObsPhotosForTaxa(taxaToUpdate, locationOptions) {
147
+ /** @type {Map<string,InatPhotoInfo[]>} */
148
+ const photos = new Map();
149
+
150
+ const meter = new ProgressMeter(
151
+ "retrieving observation photos",
152
+ taxaToUpdate.length,
153
+ );
154
+
155
+ for (let index = 0; index < taxaToUpdate.length; index++) {
156
+ const taxon = taxaToUpdate[index];
157
+ const observations = await fetchObservationsForTaxon(
158
+ taxon,
159
+ locationOptions,
160
+ );
161
+ if (observations instanceof Error) {
162
+ console.error(observations.message);
163
+ continue;
164
+ }
165
+
166
+ // Just get the CC-licensed ones, 5 per taxon should be fine (max is 20 on iNat). Whether or not
167
+ const rawPhotoInfo = observations
168
+ .map((obs) =>
169
+ obs.observation_photos.map((op) => {
170
+ return { obsId: obs.id, ...op.photo };
171
+ }),
172
+ )
173
+ .flat();
174
+
175
+ /** @type {InatPhotoInfo[]} */
176
+ const processedPhotoInfo = [];
177
+ for (const photo of rawPhotoInfo) {
178
+ if (processedPhotoInfo.length >= 5) {
179
+ break;
180
+ }
181
+ const obj = convertToCSVPhoto(photo);
182
+ if (!obj) {
183
+ continue;
184
+ }
185
+ processedPhotoInfo.push(obj);
186
+ }
187
+ photos.set(taxon.getName(), processedPhotoInfo);
188
+
189
+ meter.update(index + 1);
190
+ }
191
+
192
+ meter.stop();
193
+
194
+ return photos;
195
+ }
196
+
58
197
  /**
59
198
  * @param {import("../types.js").Taxon[]} taxaToUpdate
60
199
  * @returns {Promise<Map<string,InatPhotoInfo[]>>}
@@ -78,37 +217,17 @@ export async function getTaxonPhotos(taxaToUpdate) {
78
217
  for (const batch of chunk(taxaToUpdate, 30)) {
79
218
  const inatTaxa = await fetchInatTaxa(batch.map((t) => t.getINatID()));
80
219
  for (const iNatTaxon of inatTaxa) {
81
- const iNatTaxonPhotos = iNatTaxon.taxon_photos.filter((tp) =>
82
- ALLOWED_LICENSE_CODES.includes(tp.photo.license_code),
83
- );
84
-
85
220
  const taxonName = idMap.get(iNatTaxon.id.toString());
86
221
  if (!taxonName) {
87
222
  throw new Error(`iNat id ${iNatTaxon.id} not found`);
88
223
  }
89
224
  /** @type {InatPhotoInfo[]} */
90
225
  const taxonPhotos = [];
91
- for (const taxonPhoto of iNatTaxonPhotos) {
92
- const url = taxonPhoto.photo.medium_url || taxonPhoto.photo.url;
93
- if (!url) continue;
94
- const ext = url.split(".").at(-1);
95
- if (!ext) continue;
96
- /** @type {InatPhotoInfo} */
97
- const obj = {
98
- id: taxonPhoto.photo.id.toString(),
99
- ext: ext,
100
- licenseCode: taxonPhoto.photo.license_code,
101
- attrName:
102
- // Photographers retain copyright for most CC licenses,
103
- // except CC0, so attribution is a bit different
104
- taxonPhoto.photo.attribution.match(
105
- /\(c\) (.*?),/,
106
- )?.[1] ||
107
- taxonPhoto.photo.attribution.match(
108
- /uploaded by (.*)/,
109
- )?.[1],
110
- };
111
-
226
+ for (const taxonPhoto of iNatTaxon.taxon_photos) {
227
+ const obj = convertToCSVPhoto(taxonPhoto.photo);
228
+ if (!obj) {
229
+ continue;
230
+ }
112
231
  taxonPhotos.push(obj);
113
232
  }
114
233
  photos.set(taxonName, taxonPhotos);
@@ -122,3 +241,52 @@ export async function getTaxonPhotos(taxaToUpdate) {
122
241
 
123
242
  return photos;
124
243
  }
244
+
245
+ /**
246
+ * @param {string} licenseCode
247
+ * @returns {AllowedLicenseCode|undefined}
248
+ */
249
+ function getAllowedLicenseCode(licenseCode) {
250
+ switch (licenseCode) {
251
+ case "cc0":
252
+ case "cc-by":
253
+ case "cc-by-nc":
254
+ return licenseCode;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * @param {string} rawAttribution
260
+ * @returns {string|undefined}
261
+ */
262
+ function getAttribution(rawAttribution) {
263
+ // Photographers retain copyright for most CC licenses,
264
+ // except CC0, so attribution is a bit different
265
+ return (
266
+ rawAttribution.match(/\(c\) (.*?),/)?.[1] ||
267
+ rawAttribution.match(/uploaded by (.*)/)?.[1]
268
+ );
269
+ }
270
+
271
+ let lastQueryTime = Date.now();
272
+ /**
273
+ * @param {URL} url
274
+ * @returns {Promise<Response|Error>}
275
+ */
276
+ async function getResponse(url) {
277
+ // If less than one second since last query, delay.
278
+ const delayTime = 1050 - (Date.now() - lastQueryTime);
279
+ if (delayTime > 0) {
280
+ await sleep(delayTime);
281
+ }
282
+
283
+ try {
284
+ lastQueryTime = Date.now();
285
+ return await fetch(url);
286
+ } catch (error) {
287
+ if (error instanceof Error) {
288
+ return error;
289
+ }
290
+ throw error;
291
+ }
292
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ca-plant-list/ca-plant-list",
3
- "version": "0.4.31",
3
+ "version": "0.4.32",
4
4
  "description": "Tools to create files for a website listing plants in an area of California.",
5
5
  "license": "MIT",
6
6
  "repository": {