Allmine API
Live Stream

Live Stream history — mobil ve web

Geçmiş yayınlar client entegrasyonu

Live Stream History - Mobile/Web Integration

Migration rehberi

Yapılandırma sırası için Migration şablonu. Yeni düzenlemelerde Amaç → Önkoşullar → Endpoint → Request/Response → Hata kodları → Client adımları → İlgili sayfalar bölümlerini tercih edin.

Endpointler

  • GET /api/v1/live-stream/my-broadcasted-streams
  • GET /api/v1/live-stream/my-watched-streams
  • Auth: Authorization: Bearer <JWT> zorunlu

Kapsam

my-broadcasted-streams:

  • Kullanıcının host veya guest olarak katıldığı geçmiş yayınları döner.
  • Response item role alanı matched participant rolüne göre host veya guest olur.

my-watched-streams:

  • Kullanıcının audience olarak izlediği geçmiş yayınları döner.
  • Response item role alanı audience olur.

Ortak davranış:

  • Sadece status = ended yayınlar döner.
  • Soft-deleted yayınlar dönmez.
  • Aynı yayına tekrar giriş yapılmışsa tek item döner.
  • recordingUrl, recording veya profil replay görünürlüğü filtresi uygulanmaz.
  • Harcama/kazanç bilgisi bu endpointlerde dönmez.

History Kaydi Nasil Olusur?

History listeleri backend tarafındaki Participant kayıtlarından beslenir.

Bir yayın izleme geçmişine düşmesi için kullanıcı yayına authenticated olarak katılmalıdır:

  • REST: POST /api/v1/live-stream/join
  • Socket: /live-stream namespace joinStream
  • Socket: /stream-chat namespace joinStream

Socket bağlantılarında JWT gönderilmezse kullanıcı odaya katılsa bile kişisel watched history için participant kaydı yazılmaz.

Query

page?: number  // default: 1, min: 1
limit?: number // default: 10, min: 1, max: 100

Örnek:

GET /api/v1/live-stream/my-broadcasted-streams?page=1&limit=10
GET /api/v1/live-stream/my-watched-streams?page=2&limit=20

Response

Backend standart BaseResponseDto<T> wrapper döner. Asıl payload data içindedir. Response shape GET /api/v1/live-stream/whats-live-now ile aynıdır: data.list içinde LiveStreamResponseDto[], data.pagination içinde pagination metadata döner.

{
  "isSuccess": true,
  "statusCode": 200,
  "data": {
    "list": [
      {
        "id": "65f000000000000000000001",
        "title": "Yayin basligi",
        "liveStreamType": "solo",
        "channelName": "channel-name",
        "broadcasters": [],
        "guests": [],
        "creator": {
          "_id": "65f000000000000000000010",
          "username": "creator",
          "name": "Creator",
          "surname": "User",
          "profilePhoto": null
        },
        "thumbnailUrl": null,
        "recording": false,
        "recordingUrl": null,
        "status": "ended",
        "accessType": "free",
        "price": 0,
        "interest": "music",
        "durationGoal": null,
        "motivation": null,
        "isActiveReplayOnCreatorProfile": null,
        "replayCreditPrice": null,
        "startedAt": "2026-05-01T12:00:00.000Z",
        "plannedStartDate": null,
        "endedAt": "2026-05-01T12:30:00.000Z",
        "plannedEndDate": null,
        "createdAt": "2026-05-01T11:50:00.000Z",
        "updatedAt": "2026-05-01T12:30:00.000Z",
        "fundingGoal": null,
        "collectedFunding": null,
        "fundingPercentage": null,
        "role": "host",
        "miniCrowdFundings": []
      }
    ],
    "pagination": {
      "currentPage": 1,
      "totalPages": 1,
      "totalItems": 1,
      "itemsPerPage": 10,
      "hasNextPage": false,
      "hasPrevPage": false
    }
  },
  "errors": [],
  "timestamp": "2026-05-11T07:00:00.000Z"
}

TypeScript Tipleri

type LiveStreamRole = 'host' | 'guest' | 'audience' | null;

type Pagination = {
  currentPage: number;
  totalPages: number;
  totalItems: number;
  itemsPerPage: number;
  hasNextPage: boolean;
  hasPrevPage: boolean;
};

type PaginatedResponse<T> = {
  list: T[];
  pagination: Pagination;
};

type BaseResponseDto<T> = {
  isSuccess: boolean;
  statusCode: number;
  data: T;
  errors?: string[];
  timestamp: string;
};

type LiveStreamHistoryItem = {
  id: string;
  title: string;
  liveStreamType: 'solo' | 'duoself' | 'duocrowd';
  channelName: string;
  status: 'ended';
  accessType: 'free' | 'paid';
  role: LiveStreamRole;
  creator: unknown | null;
  guests: unknown[];
  broadcasters: unknown[];
  thumbnailUrl?: string | null;
  recording: boolean;
  recordingUrl?: string | null;
  startedAt?: string | null;
  endedAt?: string | null;
  createdAt: string;
  updatedAt: string;
};

type LiveStreamHistoryResponse = PaginatedResponse<LiveStreamHistoryItem>;

Not: LiveStreamHistoryItem aslında mevcut LiveStreamResponseDto ile aynıdır. Uygulamada zaten ortak live stream type varsa onu kullanın.

RTK Query Ornegi

Base API baseUrl değeri /api ise endpoint URL'leri /v1/... olarak kullanılır.

import { baseApi } from './baseApi';

type BaseResponseDto<T> = { data: T };

type Pagination = {
  currentPage: number;
  totalPages: number;
  totalItems: number;
  itemsPerPage: number;
  hasNextPage: boolean;
  hasPrevPage: boolean;
};

type PaginatedResponse<T> = {
  list: T[];
  pagination: Pagination;
};

type LiveStreamHistoryItem = {
  id: string;
  title: string;
  status: 'ended';
  role: 'host' | 'guest' | 'audience' | null;
  thumbnailUrl?: string | null;
  startedAt?: string | null;
  endedAt?: string | null;
};

type HistoryQuery = {
  page?: number;
  limit?: number;
};

const unwrap = <T>(response: BaseResponseDto<T> | T): T =>
  response && typeof response === 'object' && 'data' in response
    ? (response as BaseResponseDto<T>).data
    : (response as T);

export const liveStreamHistoryApi = baseApi.injectEndpoints({
  endpoints: (builder) => ({
    getMyBroadcastedStreams: builder.query<
      PaginatedResponse<LiveStreamHistoryItem>,
      HistoryQuery | void
    >({
      query: (params) => ({
        url: '/v1/live-stream/my-broadcasted-streams',
        method: 'GET',
        params: {
          page: params?.page ?? 1,
          limit: params?.limit ?? 10,
        },
      }),
      transformResponse: (
        response: BaseResponseDto<PaginatedResponse<LiveStreamHistoryItem>>,
      ) => unwrap(response),
    }),

    getMyWatchedStreams: builder.query<
      PaginatedResponse<LiveStreamHistoryItem>,
      HistoryQuery | void
    >({
      query: (params) => ({
        url: '/v1/live-stream/my-watched-streams',
        method: 'GET',
        params: {
          page: params?.page ?? 1,
          limit: params?.limit ?? 10,
        },
      }),
      transformResponse: (
        response: BaseResponseDto<PaginatedResponse<LiveStreamHistoryItem>>,
      ) => unwrap(response),
    }),
  }),
});

export const {
  useGetMyBroadcastedStreamsQuery,
  useGetMyWatchedStreamsQuery,
} = liveStreamHistoryApi;

Web Fetch Ornegi

async function getMyWatchedStreams(token: string, page = 1, limit = 10) {
  const params = new URLSearchParams({
    page: String(page),
    limit: String(limit),
  });

  const response = await fetch(`/api/v1/live-stream/my-watched-streams?${params}`, {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });

  if (!response.ok) {
    throw new Error(`History request failed: ${response.status}`);
  }

  const body = await response.json();
  return body.data as PaginatedResponse<LiveStreamHistoryItem>;
}

UI Notlari

  • Broadcasted tab: my-broadcasted-streams
  • Watched tab: my-watched-streams
  • Empty state:
    • Broadcasted: kullanıcının host/guest olarak bitmiş yayını yoktur.
    • Watched: kullanıcının audience olarak bitmiş yayını yoktur.
  • Infinite scroll için pagination.hasNextPage kullanılmalı.
  • Pull-to-refresh için page=1 tekrar çekilmeli.
  • Harcama/kazanç gösterimi bu endpointlerden beklenmemeli.

On this page