mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-18 23:11:12 +02:00
feat(tiktok): item output schemas
This commit is contained in:
parent
3c027b9f49
commit
ef3f9f2e25
3 changed files with 153 additions and 0 deletions
|
|
@ -0,0 +1,21 @@
|
||||||
|
"""Apify-compatible input and output contracts for the TikTok scraper."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .items import (
|
||||||
|
AuthorMeta,
|
||||||
|
CommentItem,
|
||||||
|
ErrorItem,
|
||||||
|
MusicMeta,
|
||||||
|
TikTokVideoItem,
|
||||||
|
VideoMeta,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"AuthorMeta",
|
||||||
|
"CommentItem",
|
||||||
|
"ErrorItem",
|
||||||
|
"MusicMeta",
|
||||||
|
"TikTokVideoItem",
|
||||||
|
"VideoMeta",
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
# ruff: noqa: N815 - field names mirror the public camelCase TikTok/Apify API
|
||||||
|
"""Output items keyed to the Clockworks TikTok actor's shape.
|
||||||
|
|
||||||
|
Every model is open (``extra="allow"``) and defaults unsourced fields to
|
||||||
|
``None``/``[]`` so the MVP can populate a reliable subset and expand the
|
||||||
|
contract additively without breaking consumers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorMeta(BaseModel):
|
||||||
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|
||||||
|
id: str | None = None
|
||||||
|
name: str | None = None
|
||||||
|
nickName: str | None = None
|
||||||
|
profileUrl: str | None = None
|
||||||
|
verified: bool | None = None
|
||||||
|
signature: str | None = None
|
||||||
|
avatar: str | None = None
|
||||||
|
privateAccount: bool | None = None
|
||||||
|
fans: int | None = None
|
||||||
|
following: int | None = None
|
||||||
|
heart: int | None = None
|
||||||
|
video: int | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class MusicMeta(BaseModel):
|
||||||
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|
||||||
|
musicId: str | None = None
|
||||||
|
musicName: str | None = None
|
||||||
|
musicAuthor: str | None = None
|
||||||
|
musicOriginal: bool | None = None
|
||||||
|
playUrl: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class VideoMeta(BaseModel):
|
||||||
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|
||||||
|
height: int | None = None
|
||||||
|
width: int | None = None
|
||||||
|
duration: int | None = None
|
||||||
|
coverUrl: str | None = None
|
||||||
|
format: str | None = None
|
||||||
|
definition: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class TikTokVideoItem(BaseModel):
|
||||||
|
"""A single scraped post (video or slideshow)."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|
||||||
|
id: str | None = None
|
||||||
|
text: str | None = None
|
||||||
|
textLanguage: str | None = None
|
||||||
|
createTime: int | None = None
|
||||||
|
createTimeISO: str | None = None
|
||||||
|
isAd: bool | None = None
|
||||||
|
|
||||||
|
authorMeta: AuthorMeta = Field(default_factory=AuthorMeta)
|
||||||
|
musicMeta: MusicMeta = Field(default_factory=MusicMeta)
|
||||||
|
videoMeta: VideoMeta = Field(default_factory=VideoMeta)
|
||||||
|
|
||||||
|
webVideoUrl: str | None = None
|
||||||
|
mediaUrls: list[str] = Field(default_factory=list)
|
||||||
|
|
||||||
|
diggCount: int | None = None
|
||||||
|
shareCount: int | None = None
|
||||||
|
playCount: int | None = None
|
||||||
|
collectCount: int | None = None
|
||||||
|
commentCount: int | None = None
|
||||||
|
|
||||||
|
hashtags: list[dict[str, Any]] = Field(default_factory=list)
|
||||||
|
mentions: list[str] = Field(default_factory=list)
|
||||||
|
|
||||||
|
isSlideshow: bool | None = None
|
||||||
|
isPinned: bool | None = None
|
||||||
|
isSponsored: bool | None = None
|
||||||
|
|
||||||
|
scrapedAt: str | None = None
|
||||||
|
|
||||||
|
def to_output(self) -> dict[str, Any]:
|
||||||
|
return self.model_dump(exclude_none=False)
|
||||||
|
|
||||||
|
|
||||||
|
class CommentItem(BaseModel):
|
||||||
|
"""A single comment or reply under a post."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|
||||||
|
id: str | None = None
|
||||||
|
text: str | None = None
|
||||||
|
videoWebUrl: str | None = None
|
||||||
|
diggCount: int | None = None
|
||||||
|
replyCommentTotal: int | None = None
|
||||||
|
createTime: int | None = None
|
||||||
|
createTimeISO: str | None = None
|
||||||
|
|
||||||
|
uid: str | None = None
|
||||||
|
uniqueId: str | None = None
|
||||||
|
nickName: str | None = None
|
||||||
|
avatar: str | None = None
|
||||||
|
|
||||||
|
repliesToId: str | None = None
|
||||||
|
scrapedAt: str | None = None
|
||||||
|
|
||||||
|
def to_output(self) -> dict[str, Any]:
|
||||||
|
return self.model_dump(exclude_none=False)
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorItem(BaseModel):
|
||||||
|
"""Per-input failure, distinguished from normal items by ``errorCode``.
|
||||||
|
|
||||||
|
Mirrors the actor's convention so a private/deleted/empty target surfaces
|
||||||
|
as an item instead of silently vanishing from the results.
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|
||||||
|
url: str | None = None
|
||||||
|
input: str | None = None
|
||||||
|
error: str | None = None
|
||||||
|
errorCode: str | None = None
|
||||||
|
|
||||||
|
def to_output(self) -> dict[str, Any]:
|
||||||
|
return self.model_dump(exclude_none=False)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue