Videos
Fetching a list of videos
You can fetch a list of videos using the following method on the client. fetchVideos returns a Query object filled with VideoInstance objects of the request or undefined in case of failure. There are a few examples provided using Vue and tailwindcss.
const videos = await client.fetchVideos(filter, order, withProducts, count, after);
// Log the title of each video.
videos.items.forEach(video => {
console.log(video.title);
})Parameters
filter: VideoFilter
Filter videos based on set criteria. Defaults to {}.
type VideoFilter = {
author?: IdType;
search?: string;
type?: string;
category?: IdType;
seller?: IdType;
status?: VideoStatus[]; // "INITIAL" | "PLANNED" | "LIVE" | "PAST" | "NOT_RECORDED"
};(optional) order: OrderType<VideoOrderField>
Order the result. Defaults to { field: "ADDED", direction: "DESC" }.
const order = {
field: "ADDED"; // "TITLE" | "ADDED" | "VIEWS" | "LIKES" | "COMMENTS" | "RECOMMENDATION"
direction: 'ASC'; // "ASC" | "DESC"
};(optional) withProducts: boolean
Include products in the query result. Defaults to false.
(optional) count: number
Number of videos to fetch. Defaults to 20.
(optional) after: string
Cursor at which to start querying. Can be obtained from _cursor property of each video. Defaults to null.
Example
Fetching a list of videos with an option to load more and a search functionality.
<script setup>
import { onMounted, ref, watch } from "vue";
import { Client, FetchClientAdapter } from "livemarket-sdk";
let client = null;
const videos = ref(null);
const search = ref('');
const fetchVideos = async () => {
videos.value = await client.fetchVideos(
{
search: search.value,
},
null,
false,
5
);
};
const fetchMore = async () => {
videos.value = await videos.value.fetchMore();
};
onMounted(() => {
// in a real-world scenario you would move this step to a separate file.
client = new Client({
token: "###YOUR_CLIENT_TOKEN##",
adapter: new FetchClientAdapter(),
});
fetchVideos();
});
watch(search, fetchVideos);
</script>
<template>
<div class="py-6">
<input
class="w-full px-4 py-2 rounded-lg mb-4"
placeholder="Type something in to search..."
v-model="search"
/>
<ul
class="list-none bg-pink-700 bg-opacity-30 p-3 rounded-lg"
v-if="videos"
>
<li class="text-lg text-bold" v-for="video in videos.items">
<div>{{ video.title }}</div>
<div class="text-sm">[ID: {{ video.id }}]</div>
</li>
</ul>
<div
class="flex justify-center items-center py-2"
v-if="!videos || videos.isFetching"
>
<div
class="w-8 h-8 border-2 border-solid border-white border-t-transparent rounded-full animate-spin"
/>
</div>
<div
class="flex justify-center items-center mt-4"
v-if="videos && videos.totalCount > videos.items.length"
>
<button
class="cursor-pointer transition-colors hover:opacity-75"
:disabled="videos.isFetching"
@click="fetchMore"
>
Load more
</button>
</div>
</div>
</template>
Fetching a single video
You can fetch a single video using fetchVideo. Returns VideoInstance on success and undefined on failure.
const video = await client.fetchVideo(globalId, options);Parameters
globalId: IdType
globalId property of the requested video.
(optional) options: FetchVideoOptions
Options for the video.
{
withProducts: true,
withComments: true,
liveChat: true,
liveUpdates: false // Live status updates for the video.
}Note:
liveChatandliveUpdatesrequire a Pusher instance to work. See Client options
Example
LiveMarket videos are hosted on Mux. In order to play them you need to install the videojs library with Mux plugin. Please refer to the Mux documentation for more information.
<script setup>
import videojs from "@mux/videojs-kit";
import "@mux/videojs-kit/dist/index.css";
import { nextTick, onMounted, ref } from "vue";
import { Client, FetchClientAdapter } from "livemarket-sdk";
import Spinner from "...";
let client = null;
const video = ref(null);
const playerElement = ref(null);
const player = ref(null);
const fetchVideo = async () => {
// Disable live chat as we aren't using it.
video.value = await client.fetchVideo("...", {
liveChat: false
});
nextTick(() => {
player.value = videojs(playerElement.value, {
timelineHoverPreviews: true,
plugins: {
mux: {
debug: true,
data: {
env_key: import.meta.env.PUBLIC_MUX_KEY,
video_title: video.value.title,
},
},
},
});
player.value.src({
src: video.value.muxId,
type: "video/mux",
});
});
};
onMounted(() => {
client = new Client({
token: "###YOUR_CLIENT_TOKEN##",
adapter: new FetchClientAdapter(),
});
fetchVideo();
});
</script>
<template>
<div class="w-full py-6 text-center">
<div v-if="video">
<h4>{{ video.title }}</h4>
<h5 class="!mt-2">{{ video.added.toLocaleDateString() }}</h5>
<div class="px-4">
<video
ref="playerElement"
class="video-js h-96 w-auto mx-auto"
controls
preload="auto"
width="100%"
></video>
</div>
<h4>Featured in this video</h4>
<div class="px-2 flex justify-start items-start w-full overflow-x-auto">
<div
v-for="videoProduct in video.videoProducts"
:key="videoProduct.product.id"
class="p-2 w-48 rounded-md transition-all hover:shadow-2xl"
>
<img
class="block w-full h-auto"
:src="videoProduct.product.thumbnail.url"
:alt="videoProduct.product.thumbnail.alt"
/>
<h5>{{ videoProduct.product.displayName }}</h5>
<h6>{{ videoProduct.product.displayPrice }}</h6>
</div>
</div>
</div>
<div class="flex justify-center items-center" v-else>
<Spinner />
</div>
</div>
</template>Chat example
This is an example of using chat associated with a video. You can combine it with the example above to create a full video page.
<script setup>
import { onMounted, ref } from "vue";
import { Client, FetchClientAdapter } from "../../../lib/livemarket-sdk";
import Spinner from "...";
import Pusher from "pusher-js";
let client = null;
const video = ref(null);
const chat = ref([]);
const chatMessage = ref("");
const nickname = ref("Test user");
const fetchVideo = async () => {
video.value = await client.fetchVideo("...", {
withProducts: false,
});
chat.value = video.value.comments?.reverse() || [];
video.value.addEventListener("new-chat-message", (e) => {
// e.details contains the message received
chat.value.unshift(e.details);
});
};
const sendChatMessage = () => {
if (!chatMessage.value || !nickname.value) {
return;
}
video.value.sendChatMessage(chatMessage.value, nickname.value);
chatMessage.value = "";
};
onMounted(() => {
client = new Client({
token: "###YOUR_CLIENT_TOKEN##",
adapter: new FetchClientAdapter(),
pusher: Pusher,
pusherKey: "###YOUR_PUSHER_KEY###",
});
fetchVideo();
});
</script>
<template>
<div class="w-full py-6 text-center">
<div v-if="video">
<h4>{{ video.title }}</h4>
<h5 class="!mt-2">{{ video.added.toLocaleDateString() }}</h5>
<form class="text-left" @submit.prevent="sendChatMessage">
<h5>Chat</h5>
<input
class="block w-full px-4 py-2 rounded-lg mb-2"
type="text"
placeholder="Nickname"
v-model="nickname"
/>
<input
class="block w-full px-4 py-2 rounded-lg mb-2"
type="text"
placeholder="Message"
v-model="chatMessage"
/>
<button class="cursor-pointer" types="submit">Send</button>
</form>
<div class="p-3 rounded-lg text-left max-h-48 overflow-y-auto">
<div v-for="message in chat">
<p>
<strong>{{ message.user.firstName || "Unknown user" }}: </strong>
{{ message.comment }}
</p>
<p>
{{ message.submitDate.toLocaleDateString() }}
</p>
</div>
</div>
</div>
<div class="flex justify-center items-center" v-else>
<Spinner />
</div>
</div>
</template>VideoInstance object
Represents a single video and it’s available actions.
{
id: ...,
globalId: "1234",
title: "A Random Video",
added: "2022-03-17T17:57:19.790706+00:00",
resultFile: ...,
isHorizontal: false,
videoStartTime: null,
status: "INITIAL",
isLiked: true,
author: ...,
videoStats: {
likes: 36,
comments: 42,
views: 9
},
videoImage: {
url: ...,
alt: null
},
comments: []
}Properties
id: IdType
Id of the video.
globalId: IdType
Secondary id of the video. May be null.
title: string
Title of the video.
author: user
Author of the video.
See User for more information.
resultFile: string
URL of the video file. May be null.
isHorizontal: boolean
Is the video in horizontal orientation?
added: Date
Video publication date. May be null.
videoStartTime: Date
Time the video started or planned to start at. May be null.
videoImage: Image
Thumbnail of the video. May be null.
See Image from more details.
videoStats: VideoStats
Number of likes, comments and views of the video. May be null.
type VideoStats = {
likes: number;
comments: number;
views: number;
};status: VideoStatus
Current status of the video. May be null.
Available statuses are: INITIAL | PLANNED | LIVE | PAST | NOT_RECORDED
videoProducts: VideoProduct[]
List of products in the video. May be null.
type VideoProduct = {
product: Product;
};See Product for more information.
comments: Comment[]
List of comments under the video.
See CommentInstance.
isLiked: boolean
Is the video liked by the current user.
(readonly) muxId: string
Mux ID of the video.
Methods
addVideoView: Promise<number | undefined>
Add a view to the video. Returns the current number of views on success or undefined on failure.
const views = await video.addVideoView();Note: You should only manually add a view to the video if it takes a center stage in your layout and was fetched using
fetchVideos(fetch a collection of videos).fetchVideoautomatically adds a view to the video.
enableLiveChat: void
Subscribes to video’s live chat. The video will receive updates to it’s comments property in real time. The VideoInstance object will also start to dispatch new-chat-message event for every message sent to the chat.
...
video.enableLiveChat();
...Note: If you’ve set
liveChatparameter totruewhen callingfetchVideo, this is already enabled and you don’t need to call this function.
enableLiveUpdates: void
Enables live updates to video status through Pusher.
...
video.enableLiveUpdates();
...dislikeVideo: Promise<boolean>
Dislike the video. Returns current isLiked value.
const isLiked = await video.dislikeVideo();likeVideo: Promise<boolean>
Like the video. Returns current isLiked value.
const isLiked = await video.likeVideo();sendChatMessage: Promise<CommentInstance | undefined>
Send a message in the video’s chat. Returns CommentInstance on success or undefined on failure.
const message = await video.sendChatMessage(message, nick);Parameters
message: string
A message to send.
(optional) nick: string
Nickname to appear next to the message. Defaults to the nickname of current TemporaryUser or overrides this nickname if set.
You can set user’s nickname beforehand. See Set user’s nickname
Events
new-chat-message
Emitted when a new message has been posted to video’s chat.
video.addEventListener('new-chat-message', (event: LMEvent<CommentInstance>) => {
const comment = event.details;
console.log(comment);
/**
* {
* id: ...,
* user: ...,
* comment: ...,
* submitDate: ...,
* isRemoved: ...
* }
*/
});CommentInstance object
Properties
id: IdType
Id of the comment.
user: User
Author of the comment. May be null.
comment: string
Content of the comment.
submitDate: Date
Date the comment was posted.
isRemoved: boolean
Was the comment removed?
Methods
isMine: boolean
Returns true if this comment belongs to the current user. Otherwise false.
comments.forEach(comment => {
if(comment.isMine()) {
console.log(`=== ${comment.comment} ===`);
}
else {
console.log(comment.comment);
}
})