openapi: 3.0.3
info:
  title: 今日看开放平台 API
  description: |
    全网热榜聚合数据接口：57 个平台热榜、跨平台话题聚类。

    - 鉴权：`Authorization: Bearer jrk_xxx`（注册登录后在[开放平台文档页](https://www.jinrikan.com/open)创建）
    - 配额：免费档 200 次/天，按东八区自然日重置
    - 响应头：`X-RateLimit-Limit` / `X-RateLimit-Remaining` / `X-RateLimit-Reset`（epoch 秒）
  version: 1.0.0
  contact:
    name: 今日看
    url: https://www.jinrikan.com/open
servers:
  - url: https://www.jinrikan.com/api
    description: 生产环境
tags:
  - name: hot
    description: 热榜数据
paths:
  /openapi/v1/nodes:
    get:
      tags: [hot]
      summary: 平台清单
      description: 返回全部可用热榜平台（id / 中文名 / 分类）
      operationId: listNodes
      security:
        - bearerAuth: []
      responses:
        "200":
          description: 平台清单
          headers:
            X-RateLimit-Limit: { $ref: "#/components/headers/X-RateLimit-Limit" }
            X-RateLimit-Remaining: { $ref: "#/components/headers/X-RateLimit-Remaining" }
            X-RateLimit-Reset: { $ref: "#/components/headers/X-RateLimit-Reset" }
          content:
            application/json:
              schema:
                type: object
                properties:
                  code: { type: integer, example: 200 }
                  total: { type: integer, example: 57 }
                  nodes:
                    type: array
                    items:
                      type: object
                      properties:
                        id: { type: string, example: weibo, description: 平台 ID（node/:platform 路径参数） }
                        name: { type: string, example: 微博 }
                        category: { type: string, example: news, enum: [news, finance, tech, video, community, game, sports, culture] }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
  /openapi/v1/node/{platform}:
    get:
      tags: [hot]
      summary: 单平台热榜
      description: 返回指定平台当前热榜条目（与网站榜单同一份 15 分钟缓存）
      operationId: getNodeHot
      security:
        - bearerAuth: []
      parameters:
        - name: platform
          in: path
          required: true
          description: 平台 ID（取自 /openapi/v1/nodes 的 id 字段）
          schema: { type: string, example: weibo }
        - name: limit
          in: query
          description: 返回条数（1-50，默认 10）
          schema: { type: integer, minimum: 1, maximum: 50, default: 10 }
      responses:
        "200":
          description: 平台热榜
          headers:
            X-RateLimit-Limit: { $ref: "#/components/headers/X-RateLimit-Limit" }
            X-RateLimit-Remaining: { $ref: "#/components/headers/X-RateLimit-Remaining" }
            X-RateLimit-Reset: { $ref: "#/components/headers/X-RateLimit-Reset" }
          content:
            application/json:
              schema:
                type: object
                properties:
                  code: { type: integer, example: 200 }
                  platform: { type: string, example: 微博 }
                  type: { type: string, example: 热搜榜 }
                  updateTime: { type: string, format: date-time }
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        rank: { type: integer, example: 1 }
                        title: { type: string }
                        hot: { type: [number, "null"], example: 1234567, description: 热度值（部分平台无此字段为 null） }
                        url: { type: string }
                        mobileUrl: { type: [string, "null"] }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404":
          description: 平台不存在
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Error" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "502":
          description: 上游源暂不可用
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Error" }
  /openapi/v1/topics:
    get:
      tags: [hot]
      summary: 跨平台话题聚类（全网总榜）
      description: 从全部平台热榜提取出现于 ≥2 平台的共同话题，按同榜平台数排序（与 /top 页同源）
      operationId: getTopics
      security:
        - bearerAuth: []
      parameters:
        - name: limit
          in: query
          description: 返回条数（1-50，默认 30）
          schema: { type: integer, minimum: 1, maximum: 50, default: 30 }
      responses:
        "200":
          description: 话题聚类结果（topics 为空数组表示数据构建中，稍后重试）
          headers:
            X-RateLimit-Limit: { $ref: "#/components/headers/X-RateLimit-Limit" }
            X-RateLimit-Remaining: { $ref: "#/components/headers/X-RateLimit-Remaining" }
            X-RateLimit-Reset: { $ref: "#/components/headers/X-RateLimit-Reset" }
          content:
            application/json:
              schema:
                type: object
                properties:
                  code: { type: integer, example: 200 }
                  message: { type: string, description: 仅数据构建中时出现 }
                  topics:
                    type: array
                    items:
                      type: object
                      properties:
                        rank: { type: integer, example: 1 }
                        keyword: { type: string, description: 话题特征词 }
                        title: { type: string, description: 代表条目标题（热度最高） }
                        hot: { type: number, description: 话题最高热度 }
                        platformCount: { type: integer, description: 同榜平台数 }
                        platforms:
                          type: array
                          description: 上榜平台明细（最多 10 条）
                          items:
                            type: object
                            properties:
                              platform: { type: string, description: 平台中文名 }
                              rank: { type: integer, description: 在该平台的排名 }
                              title: { type: string }
                              url: { type: string }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API Key（jrk_ 前缀），也可通过 ?key=jrk_xxx 查询参数传递
  headers:
    X-RateLimit-Limit:
      description: 每日配额上限
      schema: { type: integer, example: 200 }
    X-RateLimit-Remaining:
      description: 今日剩余次数
      schema: { type: integer, example: 187 }
    X-RateLimit-Reset:
      description: 配额重置时间（东八区次日 00:00，epoch 秒）
      schema: { type: integer, example: 1792972800 }
  schemas:
    Error:
      type: object
      properties:
        error: { type: boolean, example: true }
        status: { type: integer, example: 401 }
        code: { type: string, example: UNAUTHORIZED }
        message: { type: string, example: 缺少或无效的 API Key }
  responses:
    Unauthorized:
      description: 缺少或无效的 API Key
      content:
        application/json:
          schema: { $ref: "#/components/schemas/Error" }
    Forbidden:
      description: API Key 已被禁用
      content:
        application/json:
          schema: { $ref: "#/components/schemas/Error" }
    RateLimited:
      description: 今日配额已用完（东八区次日重置）
      content:
        application/json:
          schema: { $ref: "#/components/schemas/Error" }
