照片

使用 listingsapi-js SDK 为地点添加徽标、封面和图库照片,将主图标为星标,并移除过时的文件。

照片通过公开 URL 关联到地点:您托管图片,平台获取并存储图片,然后发布平台从中获取图片。每个地点保留 1 张标志图片、1 张封面图片和任意数量的附加照片,其中最多可为 4 张附加照片加星标。所有照片方法都位于 ListingsAPI 客户端实例上,并以地点 ID 限定操作范围。数字形式的地点 ID 会自动编码,因此 1800289 和 'TG9jYXRpb246MTgwMDI4OQ==' 可以互换使用。

上传成功时有 2 种返回形式。小批量上传会在当前请求中直接完成存储,并返回处理完成的媒体文件;大批量上传则会加入队列,并返回供您轮询的请求 ID。请根据是否存在 request.requestId 来选择处理分支,而不是自行统计图片数量。

fetchLocationPhotos

列出关联到地点的所有媒体文件:标志图片、封面图片和附加图片。上传前调用此方法可查看缺少哪些图片,并获取加星标和移除方法所需的照片 ID。

TypeScript
const photos = await client.fetchLocationPhotos(1800289); for (const p of photos) {console.log(p.id, p.categoryName, p.starred, p.url);}

参数

参数类型说明
locationIdstring | number要读取其照片的地点。

解析结果为 mediaFilesOfLocation 数组,默认为空数组。每个文件都包含 id、url、thumbnailUrl、categoryName(Logo、Cover 或 Additional)、categoryId、fileType、starred 和 viewsCount。没有媒体文件的地点会返回空数组,这是新建地点的正常响应,并非错误。

addLocationPhotos

将 1 张或多张图片关联到地点。每个条目都需要在 photo 中提供可公开访问的 JPEG 或 PNG URL,并在 type 中指定图片的用途。

TypeScript
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);}}

照片选项

参数类型说明
photostring平台用于获取并存储图片的公开 JPEG 或 PNG URL。字段名为 photo,不是 url。必填。
type'LOGO' | 'COVER' | 'ADDITIONAL'图片的用途。必填。
partnerMediaIdstring您为文件指定的标识符,与文件一同保存,供合作伙伴集成使用。

参数

参数类型说明
locationIdstring | number要关联媒体文件的地点。
photosPhotoInput[]要关联的图片。不得为空。

解析结果为 addLocationPhotos 载荷:success、photos、request、errors 和 clientMutationId。在当前请求中直接完成的上传中,photos 包含新增的媒体文件,每个文件都包含 id、databaseId、url、thumbnailUrl、type 和 starred,而 request 为空对象。在加入队列的上传中,photos 为空,且 request.requestId 已设置。两种情况均表示成功。

图片必须为 JPEG 或 PNG 格式,且不同用途的图片须遵守发布平台相应的尺寸规则。每个地点仅保留 1 张标志图片和 1 张封面图片,因此重新上传任意一种都会替换现有图片。请准确设置 type:图库图片应使用 ADDITIONAL。

fetchPhotoUploadStatus

轮询已加入队列的上传,直到其进入最终状态。使用 addLocationPhotos 返回的 request.requestId。

TypeScript
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);}}

参数

参数类型说明
requestIdstring加入队列的 addLocationPhotos 调用所返回的请求 ID。

载荷包含 requestId、值为 PROCESSING、SUCCESS 或 ERROR 的任务 status,以及 photos 数组,数组中的每个条目都包含 mediaId、locationId、各自的 status 和一个 errorMessage。

任务的 status 表示处理已完成,并不表示所有图片都已成功存储。SUCCESS 任务中仍可能包含被拒绝的照片,因此一旦任务不再处于 PROCESSING 状态,就应遍历 photos 并读取每个条目。每次轮询之间请间隔几秒:连续循环轮询很容易触发速率限制。仅轮询近期上传返回的 ID,因为已过期的 ID 永远不会进入最终状态。

starLocationPhotos

为附加照片加星标,使其在支持精选图片的发布平台上优先展示,或传入 false 取消星标。

TypeScript
// 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);

参数

参数类型说明
locationIdstring | number照片所属的地点。
mediaIdsstring[]要加星标或取消星标的照片 ID,来自 fetchLocationPhotos 或上传响应。在请求中以 photoIds 发送。
starredbooleantrue 表示为指定照片加星标,false 表示取消星标。

解析结果为 starUnstarLocationPhotos 载荷:success、photos 和单个 error 对象,而不是 errors 数组。每张返回的照片都包含 id、databaseId、url、thumbnailUrl、type 及其新的 starred 值。

只有 ADDITIONAL 照片可以加星标;标志图片和封面图片已属于主要图片。每个地点最多可有 4 张带星标的照片,检查时会将已有星标的照片与本次调用中的照片合计,因此超过 4 张会导致整个请求失败。

removeLocationPhotos

根据照片 ID 解除照片与地点的关联。可用此方法移除过时的图库图片,或撤销错误的导入。

TypeScript
const result = await client.removeLocationPhotos(1800289, ['TWVkaWFGaWxlOjU4Nzg5MzI=',]); console.log(result.removedCount); // 1

参数

参数类型说明
locationIdstring | number照片所属的地点。
photoIdsstring[]要解除关联的照片 ID,来自 fetchLocationPhotos 或上传响应。

解析结果为 removeLocationPhotos 载荷:removedCount、errors 和 clientMutationId。removedCount 为 0 且 errors 为 null,表示您发送的所有 ID 均未关联到该地点,您可以据此识别已被移除的 ID。

此处只能移除 ADDITIONAL 照片。要替换标志图片或封面图片,请上传新图片。移除媒体文件会解除其与地点的关联,但不一定会将文件从账户媒体库中彻底删除。

refresh_photos.ts
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');}