相片
使用 listingsapi-js SDK 為地點附加標誌、封面和相簿相片,以星號標記主圖,並移除過時的檔案。
照片透過公開 URL 附加至地點:您託管圖片,平台擷取並儲存圖片,發布平台再從中取得圖片。每個地點保留 1 張標誌、1 張封面,以及任意數量的其他照片,其中最多可為 4 張加上星號。所有照片方法都位於 ListingsAPI 用戶端執行個體上,並以地點 ID 限定操作範圍。數字形式的地點 ID 會自動編碼,因此 1800289 和 'TG9jYXRpb246MTgwMDI4OQ==' 可以互換使用。
上傳成功有 2 種形式。小批次會直接儲存,並回傳處理完成的媒體;大批次則會加入佇列,並回傳供您輪詢的請求 ID。請根據是否存在 request.requestId 來選擇處理分支,而非自行計算圖片數量。
fetchLocationPhotos
列出附加至地點的所有媒體檔案:標誌、封面和其他圖片。上傳前呼叫此方法,以查看缺少哪些圖片,並取得 star 和 remove 方法所需的照片 ID。
const photos = await client.fetchLocationPhotos(1800289); for (const p of photos) {console.log(p.id, p.categoryName, p.starred, p.url);}參數
解析結果為 mediaFilesOfLocation 陣列,預設為空陣列。每個檔案都包含 id、url、thumbnailUrl、categoryName(Logo、Cover 或 Additional)、categoryId、fileType、starred 和 viewsCount。沒有媒體的地點會回傳空陣列,這是剛建立的地點的正常回應,並非錯誤。
addLocationPhotos
將 1 張或多張圖片附加至地點。每個項目都必須在 photo 中提供可公開存取的 JPEG 或 PNG URL,並在 type 中指定圖片所佔的位置。
const result = await client.addLocationPhotos(1800289, [{ photo: 'https://cdn.example.com/brightsmile/logo.png', type: 'LOGO' },{ photo: 'https://cdn.example.com/brightsmile/storefront.jpg', type: 'ADDITIONAL' },]); if (result.request?.requestId) {// Queued: poll fetchPhotoUploadStatus with this idconsole.log('queued', result.request.requestId);} else {for (const p of result.photos ?? []) { console.log('stored', p.id, p.type);}}照片選項
參數
解析結果為 addLocationPhotos 酬載:success、photos、request、errors 和 clientMutationId。若上傳直接完成處理,photos 會包含新增的媒體,每個媒體項目都包含 id、databaseId、url、thumbnailUrl、type 和 starred,而 request 為空物件。若上傳已加入佇列,photos 會是空的,且 request.requestId 會有值。這 2 種情況都表示成功。
圖片必須為 JPEG 或 PNG,且各位置皆須遵守發布平台對該位置的尺寸規定。每個地點只保留 1 張標誌和 1 張封面,因此重新上傳任一圖片都會取代現有圖片。請依用途設定 type:圖庫圖片應放在 ADDITIONAL。
fetchPhotoUploadStatus
輪詢已加入佇列的上傳,直到處理結束。請使用 addLocationPhotos 回傳的 request.requestId。
let job = await client.fetchPhotoUploadStatus('e6c2d9d9-9a18-4015-88cf-9a4e19a6f49a'); while (job.status === 'PROCESSING') {await new Promise((resolve) => setTimeout(resolve, 5000));job = await client.fetchPhotoUploadStatus('e6c2d9d9-9a18-4015-88cf-9a4e19a6f49a');} for (const p of job.photos ?? []) {if (p.status === 'ERROR') { console.log('rejected:', p.errorMessage);}}參數
酬載包含 requestId、值為 PROCESSING、SUCCESS 或 ERROR 的作業 status,以及 photos 陣列,其中每個項目都包含 mediaId、locationId、各自的 status 和 errorMessage。
作業的 status 表示處理已完成,並不代表每張圖片都已成功儲存。SUCCESS 作業仍可能包含遭拒的照片,因此一旦作業離開 PROCESSING 狀態,請遍歷 photos 並讀取每個項目。每次輪詢之間請間隔幾秒:連續不停地輪詢很容易觸發速率限制。請只輪詢最近上傳所取得的 ID,因為過期的 ID 永遠不會進入處理結束狀態。
starLocationPhotos
為其他照片加上星號,讓照片在支援精選圖片的發布平台上優先顯示,或傳入 false 來移除星號。
// Feature a photoconst result = await client.starLocationPhotos(1800289,['TWVkaWFGaWxlOjU4Nzg5MzI='],true,); console.log(result.success, result.photos[0].starred); // Reverse itawait client.starLocationPhotos(1800289, ['TWVkaWFGaWxlOjU4Nzg5MzI='], false);參數
解析結果為 starUnstarLocationPhotos 酬載:success、photos,以及單一 error 物件,而非 errors 陣列。每張回傳的照片都包含 id、databaseId、url、thumbnailUrl、type 及其新的 starred 值。
只有 ADDITIONAL 照片可以加上星號;標誌和封面已經是主要圖片。每個地點最多可有 4 張加上星號的照片,檢查時會將已加上星號的照片與此次呼叫中的照片合併計算,因此超過 4 張會導致整個請求失敗。
removeLocationPhotos
依照片 ID 解除照片與地點的關聯。使用此方法移除過時的圖庫圖片,或復原錯誤的匯入。
const result = await client.removeLocationPhotos(1800289, ['TWVkaWFGaWxlOjU4Nzg5MzI=',]); console.log(result.removedCount); // 1參數
解析結果為 removeLocationPhotos 酬載:removedCount、errors 和 clientMutationId。若 removedCount 為 0 且 errors 為 null,表示您傳入的 ID 均未與該地點關聯,您可藉此識別已移除的 ID。
此處只能移除 ADDITIONAL 照片。若要更換標誌或封面,請上傳新圖片。移除媒體會解除它與地點的關聯,但不一定會從帳戶媒體庫中刪除該檔案。
常見的相片集更新流程
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI(); // reads LISTINGSAPI_KEY from envconst LOCATION_ID = 1800289; // Brightsmile Dental // 1. See what is already attachedconst existing = await client.fetchLocationPhotos(LOCATION_ID);const hasLogo = existing.some((p) => p.categoryName === 'Logo'); // 2. Upload only what is missing, plus the new hero shotconst uploaded = await client.addLocationPhotos(LOCATION_ID, [...(hasLogo ? [] : [{ photo: 'https://cdn.example.com/brightsmile/logo.png', type: 'LOGO' as const }]),{ photo: 'https://cdn.example.com/brightsmile/hero-2026.jpg', type: 'ADDITIONAL' as const },]); // 3. Feature the new hero shotconst hero = (uploaded.photos ?? []).find((p) => p.type === 'ADDITIONAL');if (hero) {await client.starLocationPhotos(LOCATION_ID, [hero.id], true);} // 4. Retire last season's imagesconst stale = existing.filter((p) => p.categoryName === 'Additional' && !p.starred).map((p) => p.id);if (stale.length > 0) {const removed = await client.removeLocationPhotos(LOCATION_ID, stale);console.log('removed ' + removed.removedCount + ' stale photos');}