{"id":28423,"date":"2022-03-23T22:05:54","date_gmt":"2022-03-23T22:05:54","guid":{"rendered":"http:\/\/CCTV-video-effect-using-cloudinary-and-svelte-kit"},"modified":"2022-03-23T22:05:54","modified_gmt":"2022-03-23T22:05:54","slug":"cctv-video-effect-using-cloudinary-and-svelte-kit","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/","title":{"rendered":"Creating CCVT Video Effect"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><h2>Introduction and setup<\/h2>\n<p>In this fun simple tutorial, we\u2019re going to be using <a href=\"https:\/\/cloudinary.com\/?ap=em\">Cloudinary<\/a> transformations and <a href=\"https:\/\/kit.svelte.dev\/\">SvelteKit<\/a> to apply a CCTV effect to any video.<\/p>\n<p>For those who are not familiar, <a href=\"https:\/\/kit.svelte.dev\/\">SvelteKit<\/a> is a <a href=\"https:\/\/svelte.dev\/\">Svelte<\/a> framework similar to Next.js. If you\u2019ve already written some Svelte code before, it\u2019s fairly easy to get up and running.<\/p>\n<p>You\u2019re going to need to have Node.js and NPM installed on your development environment if you want to follow along. It goes without saying that you need some working knowledge of Javascript. It\u2019s recommended that you be familiar with the basics of Svelte.<\/p>\n<blockquote>\n<p>It\u2019s important to note that SvelteKit is still in the early development stages. Certain features may be missing or buggy. You can still find some workarounds. Some notable issues include <a href=\"https:\/\/github.com\/sveltejs\/kit\/issues\/70\">file upload<\/a> and <a href=\"https:\/\/github.com\/vitejs\/vite\/issues\/3176\">loading environment variables<\/a> during SSR. The latter is more of an issue with <a href=\"https:\/\/github.com\/vitejs\/vite\">Vite<\/a> than with SvelteKit. It has, however, been addressed with Vite.js 2.7.<\/p>\n<\/blockquote>\n<p>To create a new SvelteKit project, you can run the following command in your terminal<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">npm init svelte@next cctv-video-effect-<span class=\"hljs-keyword\">with<\/span>-cloudinary\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><code>cctv-video-effect-with-cloudinary<\/code> is the name of our project. You can substitute this for any appropriate name. Just follow the prompts to complete the scaffolding. To keep things simple, choose <strong>Skeleton project<\/strong> template, <strong>No<\/strong> for typescript, <strong>Yes<\/strong> for ESLint, <strong>Yes<\/strong> for Prettier. You can, however, use whatever options you want.<\/p>\n<p>Let\u2019s understand the process, before proceeding. Ideally, you would want to allow the user to select a video file from their device, upload that video to cloudinary and apply the transformations. Because of the file upload issue that I mentioned earlier, we\u2019re not going to be doing this. Instead, we\u2019ll use a video file that is static. There\u2019s a workaround to the file upload <a href=\"https:\/\/github.com\/sveltejs\/kit\/issues\/70#issuecomment-975658485\">here<\/a> in case you are interested.<\/p>\n<h3>Cloudinary credentials<\/h3>\n<p>We need API keys to communicate with the cloudinary API. Open <a href=\"https:\/\/cloudinary.com\/?ap=em\">cloudinary<\/a> and create a free account if you do not have one yet. Proceed to log in then go to the <a href=\"https:\/\/cloudinary.com\/console?ap=em\">console page<\/a>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/hackit-africa\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1623006780\/cloudinary-dashboard.png\" alt=\"Cloudinary Dashboard\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1537\" height=\"255\"\/><\/p>\n<p>Open the SvelteKit project we created in your favorite code editor. At the root of your project, create a file called <code>.env.local<\/code>. We\u2019re going to be defining our environment variables in this file. Please <a href=\"https:\/\/kit.svelte.dev\/faq#env-vars\">read this FAQ<\/a> and <a href=\"https:\/\/dev.to\/danawoodman\/storing-environment-variables-in-sveltekit-2of3#security-note\">this blog post<\/a> before proceeding.<\/p>\n<p>Paste the following code inside <code>.env.local<\/code><\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">VITE_CLOUDINARY_CLOUD_NAME=YOUR_CLOUD_NAME\nVITE_CLOUDINARY_API_KEY=YOUR_API_KEY\nVITE_CLOUDINARY_API_SECRET=YOUR_API_SECRET\n<\/code><\/span><\/pre>\n<p>Make sure to replace <code>YOUR_CLOUD_NAME<\/code> <code>YOUR_API_KEY<\/code> and <code>YOUR_API_SECRET<\/code> with the <strong>Cloud name<\/strong>, <strong>API Key<\/strong> and <strong>API Secret<\/strong> values from the <a href=\"https:\/\/cloudinary.com\/console?ap=em\">console page<\/a>.<\/p>\n<p>We also need to install the <a href=\"https:\/\/www.npmjs.com\/package\/cloudinary\">Cloudinary Node.js SDK<\/a>. Run the following command in your terminal, at the root of your project.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm install cloudinary\n<\/code><\/span><\/pre>\n<h3>Video for upload.<\/h3>\n<p>I mentioned that we\u2019re not going to be selecting a video via a form, so we need a static video that we can use. It doesn\u2019t matter which video you use, you can just download a random video from the internet and save it inside <code>static\/videos<\/code>. Make sure to take note of the file name. To make it easier later, you can rename it to <code>video.mp4<\/code>. You can also get the full source code on my <a href=\"https:\/\/github.com\/musebe\/cctv-video-effects\/blob\/main\/static\/videos\/video.mp4\">github<\/a> with a sample video already downloaded.<\/p>\n<h2>Getting started.<\/h2>\n<p>The first thing we need is the code that we\u2019re going to use to communicate with the cloudinary SDK. Inside the <code>src<\/code> folder, create a new folder called <code>lib<\/code>. Create a new file named <code>cloudinary.js<\/code> inside <code>src\/lib<\/code> and paste the following code inside.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cloudinary'<\/span>;\n\ncloudinary.config({\n\t<span class=\"hljs-attr\">cloud_name<\/span>: <span class=\"hljs-keyword\">import<\/span>.meta.env.VITE_CLOUDINARY_CLOUD_NAME,\n\t<span class=\"hljs-attr\">api_key<\/span>: <span class=\"hljs-keyword\">import<\/span>.meta.env.VITE_CLOUDINARY_API_KEY,\n\t<span class=\"hljs-attr\">api_secret<\/span>: <span class=\"hljs-keyword\">import<\/span>.meta.env.VITE_CLOUDINARY_API_SECRET\n});\n\n<span class=\"hljs-keyword\">const<\/span> CLOUDINARY_FOLDER_NAME = <span class=\"hljs-string\">'cctv-effect-videos\/'<\/span>;\n\n<span class=\"hljs-comment\">\/**\n * Get cloudinary upload\n *\n * @param {string} id\n * @returns {Promise}\n *\/<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> handleGetCloudinaryUpload = <span class=\"hljs-function\">(<span class=\"hljs-params\">id<\/span>) =&gt;<\/span> {\n\t<span class=\"hljs-keyword\">return<\/span> cloudinary.api.resource(id, {\n\t\t<span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'upload'<\/span>,\n\t\t<span class=\"hljs-attr\">prefix<\/span>: CLOUDINARY_FOLDER_NAME,\n\t\t<span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span>\n\t});\n};\n\n<span class=\"hljs-comment\">\/**\n * Get cloudinary uploads\n * @returns {Promise}\n *\/<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> handleGetCloudinaryUploads = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\t<span class=\"hljs-keyword\">return<\/span> cloudinary.api.resources({\n\t\t<span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'upload'<\/span>,\n\t\t<span class=\"hljs-attr\">prefix<\/span>: CLOUDINARY_FOLDER_NAME,\n\t\t<span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span>\n\t});\n};\n\n<span class=\"hljs-comment\">\/**\n * Uploads a video to cloudinary and returns the upload result\n *\n * @param {{path: string; transformation?:TransformationOptions;publicId?: string; folder?: boolean; }} resource\n *\/<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> handleCloudinaryUpload = <span class=\"hljs-function\">(<span class=\"hljs-params\">resource<\/span>) =&gt;<\/span> {\n\t<span class=\"hljs-keyword\">return<\/span> cloudinary.uploader.upload(resource.path, {\n\t\t<span class=\"hljs-comment\">\/\/ Folder to store video in<\/span>\n\t\t<span class=\"hljs-attr\">folder<\/span>: resource.folder ? CLOUDINARY_FOLDER_NAME : <span class=\"hljs-literal\">null<\/span>,\n\t\t<span class=\"hljs-comment\">\/\/ Public id of video.<\/span>\n\t\t<span class=\"hljs-attr\">public_id<\/span>: resource.publicId,\n\t\t<span class=\"hljs-comment\">\/\/ Type of resource<\/span>\n\t\t<span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'auto'<\/span>,\n\t\t<span class=\"hljs-comment\">\/\/ Transformation to apply to the video<\/span>\n\t\t<span class=\"hljs-attr\">transformation<\/span>: resource.transformation\n\t});\n};\n\n<span class=\"hljs-comment\">\/**\n * Deletes resources from cloudinary. Takes in an array of public ids\n * @param {string&#91;]} ids\n *\/<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> handleCloudinaryDelete = <span class=\"hljs-function\">(<span class=\"hljs-params\">ids<\/span>) =&gt;<\/span> {\n\t<span class=\"hljs-keyword\">return<\/span> cloudinary.api.delete_resources(ids, {\n\t\t<span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span>\n\t});\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s go over that code. We import the v2 API from the SDK. You can leave it as <code>v2<\/code>, however, for readability, we rename it to <code>cloudinary<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ import { v2 } from 'cloudinary';<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cloudinary'<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We then proceed to initialize the SDK by calling the <code>.config<\/code> method and passing the cloud name, api key, and api secret.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">cloudinary<\/span><span class=\"hljs-selector-class\">.config<\/span>({\n\t<span class=\"hljs-attribute\">cloud_name<\/span>: import.meta.env.VITE_CLOUDINARY_CLOUD_NAME,\n\tapi_key: import.meta.env.VITE_CLOUDINARY_API_KEY,\n\tapi_secret: import.meta.env.VITE_CLOUDINARY_API_SECRET\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The way we reference the environment variables looks a bit weird. If you\u2019re coming from Node.js, you\u2019re probably used to seeing something like<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">process<\/span><span class=\"hljs-selector-class\">.env<\/span><span class=\"hljs-selector-class\">.VARIABLE_NAME<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Like I mentioned before, vite.js had some <a href=\"https:\/\/github.com\/vitejs\/vite\/issues\/3176\">issue<\/a> with handling environment variables server-side. Read <a href=\"https:\/\/vitejs.dev\/guide\/env-and-mode.html#env-variables\">this guide<\/a> for more information on how Vite handles these variables.<\/p>\n<blockquote>\n<p>Make sure not to use this syntax anywhere in your client-side code for sensitive variables.<\/p>\n<\/blockquote>\n<p>We also define a folder where cloudinary is going to store all our uploaded videos.<\/p>\n<p>The <code>handleGetCloudinaryUpload<\/code> function calls the <code>api.resource<\/code> method to get a single resource from cloudinary. Read about the API and options that you can pass <a href=\"https:\/\/cloudinary.com\/documentation\/admin_api#get_the_details_of_a_single_resource\">here<\/a><\/p>\n<p><code>handleGetCloudinaryUploads<\/code> calls the <code>api.resources<\/code> method to get all resources from a folder on cloudinary. Read about the API and options that you can pass <a href=\"https:\/\/cloudinary.com\/documentation\/admin_api#get_resources\">here<\/a><\/p>\n<p><code>handleCloudinaryUpload<\/code> takes in an object that contains the path to the file that we want to upload and an optional transformation array. It calls the <code>uploader.upload<\/code> method on the SDK to upload the file. Read the <a href=\"https:\/\/cloudinary.com\/documentation\/image_upload_api_reference\">upload api reference<\/a>.<\/p>\n<p><code>handleCloudinaryDelete<\/code> deletes resources from cloudinary by passing an array of public IDs to the <code>api.delete_resources<\/code> method. Read about it in the <a href=\"https:\/\/cloudinary.com\/documentation\/admin_api#delete_resources\">cloudianry admin docs<\/a>.<\/p>\n<p>That is it for the cloudinary bit.<\/p>\n<hr \/>\n<p>Now let\u2019s create some endpoints that we can call from our front-end. A SvelteKit application can have both pages and endpoints. Any file inside the <code>src\/routes<\/code> directory that ends with a <code>.svelte<\/code> extension is automatically a page. On the other hand, any file inside <code>src\/routes<\/code> that ends with a <code>.js<\/code> or a <code>.ts<\/code> extension is an endpoint.<\/p>\n<p>Create a folder called <code>api<\/code> under <code>src\/routes<\/code>. This folder will hold all of our endpoints. Since SvelteKit uses a file-based routing system, it means that all our endpoints will begin with <code>\/api<\/code>.<\/p>\n<p>Create a folder called <code>videos<\/code> under <code>src\/routes\/api<\/code>. Inside <code>src\/routes\/api\/videos<\/code> create a new file called <code>index.js<\/code>. This file will handle HTTP requests to the endpoint <code>\/api\/videos<\/code>. Paste the following code inside <code>src\/routes\/api\/videos\/index.js<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { handleCloudinaryUpload, handleGetCloudinaryUploads } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'$lib\/cloudinary'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">get<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\t<span class=\"hljs-keyword\">try<\/span> {\n\t\t<span class=\"hljs-keyword\">const<\/span> uploads = <span class=\"hljs-keyword\">await<\/span> handleGetCloudinaryUploads();\n\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: <span class=\"hljs-number\">200<\/span>,\n\t\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\t\t<span class=\"hljs-attr\">result<\/span>: uploads\n\t\t\t}\n\t\t};\n\t} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\t\t<span class=\"hljs-built_in\">console<\/span>.error(error);\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: error?.statusCode ?? <span class=\"hljs-number\">400<\/span>,\n\t\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\t\terror\n\t\t\t}\n\t\t};\n\t}\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">post<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\t<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">generateLayer<\/span>(<span class=\"hljs-params\">text, gravity, color = <span class=\"hljs-string\">'#ffffff'<\/span><\/span>) <\/span>{\n\t\t<span class=\"hljs-keyword\">return<\/span> &#91;\n\t\t\t{\n\t\t\t\tcolor,\n\t\t\t\t<span class=\"hljs-attr\">overlay<\/span>: {\n\t\t\t\t\t<span class=\"hljs-attr\">font_family<\/span>: <span class=\"hljs-string\">'Courier'<\/span>,\n\t\t\t\t\t<span class=\"hljs-attr\">font_size<\/span>: <span class=\"hljs-number\">15<\/span>,\n\t\t\t\t\t<span class=\"hljs-attr\">font_weight<\/span>: <span class=\"hljs-string\">'bold'<\/span>,\n\t\t\t\t\ttext\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t<span class=\"hljs-attr\">flags<\/span>: <span class=\"hljs-string\">'layer_apply'<\/span>,\n\t\t\t\tgravity,\n\t\t\t\t<span class=\"hljs-attr\">x<\/span>: <span class=\"hljs-string\">'15'<\/span>,\n\t\t\t\t<span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-string\">'15'<\/span>\n\t\t\t}\n\t\t];\n\t}\n\n\t<span class=\"hljs-keyword\">try<\/span> {\n\t\t<span class=\"hljs-keyword\">const<\/span> date = <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>();\n\n\t\t<span class=\"hljs-comment\">\/\/ Path to the video.<\/span>\n\t\t<span class=\"hljs-keyword\">const<\/span> videoPath = <span class=\"hljs-string\">'static\/videos\/video.mp4'<\/span>;\n\n\t\t<span class=\"hljs-comment\">\/\/ Upload the video to Cloudinary<\/span>\n\t\t<span class=\"hljs-keyword\">const<\/span> uploadResponse = <span class=\"hljs-keyword\">await<\/span> handleCloudinaryUpload({\n            <span class=\"hljs-attr\">path<\/span>: videoPath,\n            <span class=\"hljs-attr\">folder<\/span>: <span class=\"hljs-literal\">true<\/span>,\n            <span class=\"hljs-attr\">transformation<\/span>: &#91;\n                <span class=\"hljs-comment\">\/\/ Crop the video<\/span>\n                {\n                    <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">500<\/span>,\n                    <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">'scale'<\/span>\n                },\n                <span class=\"hljs-comment\">\/\/ Add a border<\/span>\n                {\n                    <span class=\"hljs-attr\">border<\/span>: <span class=\"hljs-string\">'5px_solid_rgb:00ffffff'<\/span>\n                },\n                <span class=\"hljs-comment\">\/\/ Add some visual noise<\/span>\n                {\n                    <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">'noise:50'<\/span>\n                },\n                <span class=\"hljs-comment\">\/\/ Reduce the saturation<\/span>\n                {\n                    <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">'saturation:-100'<\/span>\n                },\n                <span class=\"hljs-comment\">\/\/ Modify the contrast<\/span>\n                {\n                    <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">'contrast:50'<\/span>\n                },\n                ...generateLayer(\n                    <span class=\"hljs-string\">`<span class=\"hljs-subst\">${date.getDate()}<\/span>-<span class=\"hljs-subst\">${date.getMonth() + <span class=\"hljs-number\">1<\/span>}<\/span>-<span class=\"hljs-subst\">${date.getFullYear()}<\/span>`<\/span>,\n                    <span class=\"hljs-string\">'north_west'<\/span>\n                ),\n                ...generateLayer(<span class=\"hljs-string\">'REC'<\/span>, <span class=\"hljs-string\">'north_east'<\/span>, <span class=\"hljs-string\">'#ff0000'<\/span>),\n                ...generateLayer(<span class=\"hljs-string\">'Camera 1'<\/span>, <span class=\"hljs-string\">'south_east'<\/span>)\n            ]\n        });\n\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: <span class=\"hljs-number\">200<\/span>,\n\t\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\t\t<span class=\"hljs-attr\">result<\/span>: uploadResponse\n\t\t\t}\n\t\t};\n\t} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: error?.statusCode ?? <span class=\"hljs-number\">400<\/span>,\n\t\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\t\terror\n\t\t\t}\n\t\t};\n\t}\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>When handling requests of a particular verb\/type we need to export a function corresponding to the HTTP verb. For example, to handle GET requests we need to export a function called <code>get<\/code>, to handle POST requests we need to export a function called <code>post<\/code> and so on. The only exception is the DELETE verb where we use <code>del<\/code> instead since delete is a reserved keyword. You can get more information on this in the <a href=\"https:\/\/kit.svelte.dev\/docs#routing-endpoints\">docs<\/a>.<\/p>\n<p>In our case, when we receive GET requests we want to get all uploads by calling the <code>handleGetCloudinaryUploads<\/code> function that we created earlier.<\/p>\n<p>When we receive POST requests we want to upload the video that we saved inside <code>static\/videos<\/code>. Inside our <code>post<\/code> function, we have a function called <code>generateLayer<\/code>. This function will generate the transformation objects we need to pass to cloudinary. The transformation objects are passed to the transformation array in the <code>handleCloudinaryUpload<\/code> function that we created earlier. This is then passed to the <code>uploader.upload<\/code> method on the cloudinary SDK. Read about the <a href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference\">transformation api<\/a>. Our CCTV video will have some text: the date, recording status, and camera number. These are the layers that we are generating using the <code>generateLayer<\/code> function. Read this guide on <a href=\"https:\/\/cloudinary.com\/documentation\/video_manipulation_and_delivery#adding_text_captions\">adding text overlays to videos<\/a> with cloudinary transformations.<\/p>\n<p>If you downloaded a video to <code>static\/videos<\/code> and gave it a name other than <code>video.mp4<\/code> remember to change the following line to match the name of your video.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ Path to the video.<\/span>\n<span class=\"hljs-keyword\">const<\/span> videoPath = <span class=\"hljs-string\">'static\/videos\/video.mp4'<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The following piece of code is responsible for making the upload to cloudinary.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ Upload the video to Cloudinary<\/span>\n<span class=\"hljs-keyword\">const<\/span> uploadResponse = <span class=\"hljs-keyword\">await<\/span> handleCloudinaryUpload({\n    <span class=\"hljs-attr\">path<\/span>: videoPath,\n    <span class=\"hljs-attr\">folder<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">transformation<\/span>: &#91;\n        <span class=\"hljs-comment\">\/\/ Crop the video<\/span>\n        {\n            <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">500<\/span>,\n            <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">'scale'<\/span>\n        },\n        <span class=\"hljs-comment\">\/\/ Add a border<\/span>\n        {\n            <span class=\"hljs-attr\">border<\/span>: <span class=\"hljs-string\">'5px_solid_rgb:00ffffff'<\/span>\n        },\n        <span class=\"hljs-comment\">\/\/ Add some visual noise<\/span>\n        {\n            <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">'noise:50'<\/span>\n        },\n        <span class=\"hljs-comment\">\/\/ Reduce the saturation<\/span>\n        {\n            <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">'saturation:-100'<\/span>\n        },\n        <span class=\"hljs-comment\">\/\/ Modify the contrast<\/span>\n        {\n            <span class=\"hljs-attr\">effect<\/span>: <span class=\"hljs-string\">'contrast:50'<\/span>\n        },\n        ...generateLayer(\n            <span class=\"hljs-string\">`<span class=\"hljs-subst\">${date.getDate()}<\/span>-<span class=\"hljs-subst\">${date.getMonth() + <span class=\"hljs-number\">1<\/span>}<\/span>-<span class=\"hljs-subst\">${date.getFullYear()}<\/span>`<\/span>,\n            <span class=\"hljs-string\">'north_west'<\/span>\n        ),\n        ...generateLayer(<span class=\"hljs-string\">'REC'<\/span>, <span class=\"hljs-string\">'north_east'<\/span>, <span class=\"hljs-string\">'#ff0000'<\/span>),\n        ...generateLayer(<span class=\"hljs-string\">'Camera 1'<\/span>, <span class=\"hljs-string\">'south_east'<\/span>)\n    ]\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Pay attention to the transformation array. The first thing we do is crop the video so that we have a consistent width for all videos. Read about this <a href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference#c_crop_resize\">here<\/a>. Next, we add a border to our video. Read about how to do that <a href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference#bo_border\">here<\/a>. We then proceed to add some visual noise to the video. Read about how to do that <a href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference#e_noise\">here<\/a>. The other thing is to modify the saturation and contrast so that we have a black and white effect. Read about that <a href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference#e_saturation\">here<\/a> and <a href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference#e_contrast\">here<\/a>. We also have the last three transformations that are being generated by the <code>generateLayer<\/code> function. The first displays the date at the top left, the second displays the text <strong>REC<\/strong> on the top right, and the third displays the text <strong>Camera 1<\/strong> on the bottom right.<\/p>\n<p>We then return a successful response or an error. Read about this from the <a href=\"https:\/\/kit.svelte.dev\/docs#:~:text=The%20job%20of%20this%20function%20is%20to%20return%20a%20%7B%20status%2C%20headers%2C%20body%20%7D%20object%20representing%20the%20response%2C%20where%20status%20is%20an%20HTTP%20status%20code%3A\">SvelteKit docs<\/a>.<\/p>\n<hr \/>\n<p>Create a new file called <code>[...id].js<\/code> under <code>src\/routes\/api\/videos<\/code>. This file will handle all HTTP requests made to the endpoint <code>\/api\/videos\/:id<\/code>. Paste the following code inside <code>src\/routes\/api\/videos\/[...id].js<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { handleCloudinaryDelete, handleGetCloudinaryUpload } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'$lib\/cloudinary'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">get<\/span>(<span class=\"hljs-params\">{ params }<\/span>) <\/span>{\n\t<span class=\"hljs-keyword\">try<\/span> {\n\t\t<span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> handleGetCloudinaryUpload(params.id);\n\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: <span class=\"hljs-number\">200<\/span>,\n\t\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\t\tresult\n\t\t\t}\n\t\t};\n\t} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: error?.statusCode ?? <span class=\"hljs-number\">400<\/span>,\n\t\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\t\terror\n\t\t\t}\n\t\t};\n\t}\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">del<\/span>(<span class=\"hljs-params\">{ params }<\/span>) <\/span>{\n\t<span class=\"hljs-keyword\">try<\/span> {\n\t\t<span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> handleCloudinaryDelete(&#91;params.id]);\n\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: <span class=\"hljs-number\">200<\/span>,\n\t\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\t\tresult\n\t\t\t}\n\t\t};\n\t} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: error?.statusCode ?? <span class=\"hljs-number\">400<\/span>,\n\t\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\t\terror\n\t\t\t}\n\t\t};\n\t}\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is very similar to <code>src\/routes\/api\/videos\/index.js<\/code> save for the file name syntax and that we\u2019re handling GET requests and DELETE requests.<\/p>\n<p><code>get<\/code> calls <code>handleGetCloudinaryUpload<\/code> to get a specific resource using its public ID.<\/p>\n<p><code>del<\/code> passes a public id to <code>handleCloudinaryDelete<\/code> and deletes the resource with that public ID.<\/p>\n<p>Regarding the syntax, you need to understand <a href=\"https:\/\/kit.svelte.dev\/docs#routing-advanced-rest-parameters\">rest parameters<\/a>. We could have used the syntax for dynamic routes and named it as <code>[id].js<\/code> but this would have only matched <code>\/api\/videos\/:id<\/code>. We want to match all routes that come after <code>\/api\/videos\/<\/code> for example <code>\/api\/videos\/:id<\/code>, <code>\/api\/videos\/:id\/someAction<\/code>, <code>\/api\/videos\/:id\/someAction\/:anotherId<\/code>. In other words, we want to use the <a href=\"https:\/\/kit.svelte.dev\/docs#routing-advanced-rest-parameters\">rest parameters<\/a> syntax when we expect a route to have multiple dynamic parameters.<\/p>\n<p>That\u2019s it for the backend.<\/p>\n<hr \/>\n<p>Remember that client-side pages and components end in the extension <code>.svelte<\/code>.<\/p>\n<p>Open <code>src\/app.html<\/code> and add the following style tag to the head.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n    <span class=\"hljs-selector-tag\">body<\/span> {\n        <span class=\"hljs-attribute\">font-family<\/span>: sans-serif;\n        <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span>;\n        <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0<\/span>;\n    }\n\n    <span class=\"hljs-selector-pseudo\">:root<\/span> {\n        <span class=\"hljs-attribute\">--color-primary<\/span>: <span class=\"hljs-number\">#ff00ff<\/span>;\n    }\n\n    * {\n        <span class=\"hljs-attribute\">box-sizing<\/span>: border-box;\n    }\n\n    <span class=\"hljs-selector-tag\">button<\/span> {\n        <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">20px<\/span>;\n        <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">50px<\/span>;\n        <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> solid <span class=\"hljs-number\">#ccc<\/span>;\n        <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#ffffff<\/span>;\n        <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1.2rem<\/span>;\n        <span class=\"hljs-attribute\">font-weight<\/span>: bold;\n        <span class=\"hljs-attribute\">cursor<\/span>: pointer;\n    }\n\n    <span class=\"hljs-selector-tag\">button<\/span><span class=\"hljs-selector-pseudo\">:disabled<\/span> {\n        <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#cfcfcf<\/span>;\n    }\n\n    <span class=\"hljs-selector-tag\">button<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span><span class=\"hljs-selector-pseudo\">:not(<\/span><span class=\"hljs-selector-attr\">&#91;disabled]<\/span>) {\n        <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#ffffff<\/span>;\n        <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-built_in\">var<\/span>(--color-primary);\n    }\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Create a file called <code>__layout.svelte<\/code> inside <code>src\/routes\/<\/code> folder. Paste the following code inside <code>src\/routes\/__layout.svelte<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">nav<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\/\"<\/span>&gt;<\/span>Home<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\/videos\"<\/span>&gt;<\/span>Videos<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">nav<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">slot<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n\t<span class=\"hljs-selector-tag\">nav<\/span> {\n\t\t<span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#000000<\/span>;\n\t\t<span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#fff<\/span>;\n\t\t<span class=\"hljs-attribute\">display<\/span>: flex;\n\t\t<span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">100px<\/span>;\n\t}\n\n\t<span class=\"hljs-selector-tag\">nav<\/span> <span class=\"hljs-selector-tag\">ul<\/span> {\n\t\t<span class=\"hljs-attribute\">display<\/span>: flex;\n\t\t<span class=\"hljs-attribute\">flex<\/span>: <span class=\"hljs-number\">1<\/span>;\n\t\t<span class=\"hljs-attribute\">justify-content<\/span>: center;\n\t\t<span class=\"hljs-attribute\">align-items<\/span>: center;\n\t\t<span class=\"hljs-attribute\">list-style<\/span>: none;\n\t\t<span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">8px<\/span>;\n\t\t<span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span>;\n\t\t<span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0<\/span>;\n\t}\n\n\t<span class=\"hljs-selector-tag\">nav<\/span> <span class=\"hljs-selector-tag\">ul<\/span> <span class=\"hljs-selector-tag\">li<\/span> <span class=\"hljs-selector-tag\">a<\/span> {\n\t\t<span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">10px<\/span> <span class=\"hljs-number\">20px<\/span>;\n\t\t<span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#000000<\/span>;\n\t\t<span class=\"hljs-attribute\">display<\/span>: block;\n\t\t<span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#ffffff<\/span>;\n\t\t<span class=\"hljs-attribute\">text-decoration<\/span>: none;\n\t\t<span class=\"hljs-attribute\">font-weight<\/span>: bold;\n\t}\n\n\t<span class=\"hljs-selector-tag\">nav<\/span> <span class=\"hljs-selector-tag\">ul<\/span> <span class=\"hljs-selector-tag\">li<\/span> <span class=\"hljs-selector-tag\">a<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n\t\t<span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#ffffff<\/span>;\n\t\t<span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-built_in\">var<\/span>(--color-primary);\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is what\u2019s called a <a href=\"https:\/\/kit.svelte.dev\/docs#layouts\">layout component<\/a>. This component will be applied to every page. In case you\u2019re not familiar with svelte slots and component composition, check out <a href=\"https:\/\/svelte.dev\/tutorial\/slots\">this tutorial<\/a> from the svelte website. Similarly, we also need an <a href=\"https:\/\/kit.svelte.dev\/docs#layouts-error-pages\">error page layout<\/a> to show whenever there\u2019s an error. Create a file called <code>__error.svelte<\/code> inside <code>src\/routes<\/code> and paste the following code inside.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">tryAgain<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\t\t<span class=\"hljs-built_in\">window<\/span>.location.reload();\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"wrapper\"<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">b<\/span>&gt;<\/span>Something went wrong<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">b<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span> \/&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">on:click<\/span>|<span class=\"hljs-attr\">preventDefault<\/span>=<span class=\"hljs-string\">{tryAgain}<\/span>&gt;<\/span>Try Again<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n\t<span class=\"hljs-selector-class\">.wrapper<\/span> {\n\t\t<span class=\"hljs-attribute\">display<\/span>: flex;\n\t\t<span class=\"hljs-attribute\">flex-direction<\/span>: column;\n\t\t<span class=\"hljs-attribute\">align-items<\/span>: center;\n\t\t<span class=\"hljs-attribute\">justify-content<\/span>: center;\n\t\t<span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">100vh<\/span> - <span class=\"hljs-number\">100px<\/span>);\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Paste the following code inside <code>src\/routes\/index.svelte<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">import<\/span> { goto } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'$app\/navigation'<\/span>;\n\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> isLoading;\n\n\t<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">generateVideo<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\t\t<span class=\"hljs-keyword\">try<\/span> {\n\t\t\tisLoading = <span class=\"hljs-literal\">true<\/span>;\n\n\t\t\t<span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">'\/api\/videos'<\/span>, {\n\t\t\t\t<span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'POST'<\/span>\n\t\t\t});\n\n\t\t\t<span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> response.json();\n\n\t\t\t<span class=\"hljs-keyword\">if<\/span> (!response.ok) {\n\t\t\t\t<span class=\"hljs-keyword\">throw<\/span> data;\n\t\t\t}\n\n\t\t\tgoto(<span class=\"hljs-string\">'\/videos\/'<\/span>, { <span class=\"hljs-attr\">replaceState<\/span>: <span class=\"hljs-literal\">false<\/span> });\n\t\t} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\t\t\t<span class=\"hljs-built_in\">console<\/span>.error(error);\n\t\t} <span class=\"hljs-keyword\">finally<\/span> {\n\t\t\tisLoading = <span class=\"hljs-literal\">false<\/span>;\n\t\t}\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"wrapper\"<\/span>&gt;<\/span>\n\t{#if isLoading}\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"loading\"<\/span>&gt;<\/span>\n\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">i<\/span>&gt;<\/span>Loading. Please be patient.<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">i<\/span>&gt;<\/span>\n\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">hr<\/span> \/&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\t{\/if}\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>CCTV Video effect with cloudinary<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Apply CCTV effect to any video using cloudinary transformations<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>You can change the video by editing the video, video.mp4 inside \/static\/videos\/<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"actions\"<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">on:click<\/span>|<span class=\"hljs-attr\">preventDefault<\/span>=<span class=\"hljs-string\">{generateVideo}<\/span> <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{isLoading}<\/span>&gt;<\/span>Convert video<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>or<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\/videos\"<\/span>&gt;<\/span>View generated videos<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.loading<\/span> {\n\t\t<span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-built_in\">var<\/span>(--color-primary);\n\t}\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> {\n\t\t<span class=\"hljs-attribute\">min-height<\/span>: <span class=\"hljs-number\">100vh<\/span>;\n\t\t<span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n\t\t<span class=\"hljs-attribute\">display<\/span>: flex;\n\t\t<span class=\"hljs-attribute\">flex-flow<\/span>: column;\n\t\t<span class=\"hljs-attribute\">justify-content<\/span>: center;\n\t\t<span class=\"hljs-attribute\">align-items<\/span>: center;\n\t\t<span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#ffffff<\/span>;\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>generateVideo<\/code> function is called when the user clicks on the Convert Video button. The function makes a POST request to the <code>\/api\/videos<\/code> endpoint that we created. The endpoint will make the upload to cloudinary and apply the transformations we need to achieve the CCTV effect.<\/p>\n<blockquote>\n<p>I am assuming that you\u2019re familiar with the syntax for svelte components. For this reason, I won\u2019t go into too much detail.<\/p>\n<\/blockquote>\n<hr \/>\n<p>Create a folder called <code>videos<\/code> under <code>src\/routes\/videos<\/code>. <strong>Please note that this is a different videos folder from the one inside the api folder.<\/strong> Create a file called <code>index.svelte<\/code> inside <code>src\/routes\/videos<\/code> and paste the following code inside.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">import<\/span> { onMount } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'svelte'<\/span>;\n\n\t<span class=\"hljs-keyword\">let<\/span> isLoading = <span class=\"hljs-literal\">false<\/span>;\n\t<span class=\"hljs-keyword\">let<\/span> videos = &#91;];\n\n\tonMount(<span class=\"hljs-keyword\">async<\/span> () =&gt; {\n\t\t<span class=\"hljs-keyword\">try<\/span> {\n\t\t\tisLoading = <span class=\"hljs-literal\">true<\/span>;\n\n\t\t\t<span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">'\/api\/videos'<\/span>, {\n\t\t\t\t<span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'GET'<\/span>\n\t\t\t});\n\n\t\t\t<span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> response.json();\n\n\t\t\t<span class=\"hljs-keyword\">if<\/span> (!response.ok) {\n\t\t\t\t<span class=\"hljs-keyword\">throw<\/span> data;\n\t\t\t}\n\n\t\t\tvideos = data.result.resources;\n\t\t} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\t\t\t<span class=\"hljs-built_in\">console<\/span>.error(error);\n\t\t} <span class=\"hljs-keyword\">finally<\/span> {\n\t\t\tisLoading = <span class=\"hljs-literal\">false<\/span>;\n\t\t}\n\t});\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n{#if videos.length &gt; 0}\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"wrapper\"<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"videos\"<\/span>&gt;<\/span>\n\t\t\t{#each videos as video (video.public_id)}\n\t\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video\"<\/span>&gt;<\/span>\n\t\t\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"thumbnail\"<\/span>&gt;<\/span>\n\t\t\t\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{video.secure_url.replace(<\/span>'<span class=\"hljs-attr\">.mp4<\/span>', '<span class=\"hljs-attr\">.jpg<\/span>')} <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">{video.secure_url}<\/span> \/&gt;<\/span>\n\t\t\t\t\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\t\t\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"actions\"<\/span>&gt;<\/span>\n\t\t\t\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{<\/span>`\/<span class=\"hljs-attr\">videos<\/span>\/${<span class=\"hljs-attr\">video.public_id<\/span>}`}&gt;<\/span>Open Video<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n\t\t\t\t\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\t\t\t\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\t\t\t{\/each}\n\t\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n{:else}\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"no-videos\"<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">b<\/span>&gt;<\/span>No videos yet<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">b<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span> \/&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\/\"<\/span>&gt;<\/span>Generate video<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n{\/if}\n\n{#if isLoading &amp;&amp; videos.length === 0}\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"loading\"<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">b<\/span>&gt;<\/span>Loading...<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">b<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n{\/if}\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.videos<\/span> {\n\t\t<span class=\"hljs-attribute\">display<\/span>: flex;\n\t\t<span class=\"hljs-attribute\">flex-flow<\/span>: row wrap;\n\t\t<span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">20px<\/span>;\n\t\t<span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">20px<\/span>;\n\t}\n\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.videos<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.video<\/span> {\n\t\t<span class=\"hljs-attribute\">flex<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">1<\/span> <span class=\"hljs-number\">400px<\/span>;\n\t\t<span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">#ccc<\/span> <span class=\"hljs-number\">1px<\/span> solid;\n\t\t<span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">5px<\/span>;\n\t}\n\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.videos<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.video<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.thumbnail<\/span> {\n\t\t<span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n\t}\n\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.videos<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.video<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.thumbnail<\/span> <span class=\"hljs-selector-tag\">img<\/span> {\n\t\t<span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n\t}\n\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.videos<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.video<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.actions<\/span> {\n\t\t<span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">10px<\/span>;\n\t}\n\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.loading<\/span>,\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.no-videos<\/span> {\n\t\t<span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">100vh<\/span> - <span class=\"hljs-number\">100px<\/span>);\n\t\t<span class=\"hljs-attribute\">display<\/span>: flex;\n\t\t<span class=\"hljs-attribute\">flex-flow<\/span>: column;\n\t\t<span class=\"hljs-attribute\">align-items<\/span>: center;\n\t\t<span class=\"hljs-attribute\">justify-content<\/span>: center;\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>onMount<\/code> function is run when a svelte component is mounted to the DOM. Read about it <a href=\"https:\/\/svelte.dev\/docs#onMount\">here<\/a>. The function makes a GET request to our <code>\/api\/videos<\/code> endpoint and fetches all uploaded videos. It then updates the video\u2019s array\/state with the result. On this page, we\u2019re not actually showing the videos because we don\u2019t want to load all those videos on one page. Instead, we\u2019re using a clever cloudinary trick to <a href=\"https:\/\/cloudinary.com\/documentation\/video_manipulation_and_delivery#generating_video_thumbnails\">generate thumbnails for the videos<\/a>. By changing the extension of the video from <code>.mp4<\/code> to <code>.jpg<\/code>, cloudinary generates a thumbnail for us.<\/p>\n<hr \/>\n<p>Let\u2019s now create a page to show individual videos. Create a new file called <code>[...id].svelte<\/code> under <code>src\/routes\/videos\/<\/code>. This syntax, just like the one for <code>src\/routes\/api\/videos\/[...id].js<\/code>, is for multiple dynamic parameters, only this time we\u2019re doing it on the client-side. Paste the following inside <code>src\/routes\/videos\/[...id].svelte<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">context<\/span>=<span class=\"hljs-string\">\"module\"<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">load<\/span>(<span class=\"hljs-params\">{ page, fetch }<\/span>) <\/span>{\n\t\t<span class=\"hljs-keyword\">try<\/span> {\n\t\t\t<span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">`\/api\/videos\/<span class=\"hljs-subst\">${page.params.id}<\/span>`<\/span>, {\n\t\t\t\t<span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'GET'<\/span>\n\t\t\t});\n\n\t\t\t<span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> response.json();\n\n\t\t\t<span class=\"hljs-keyword\">if<\/span> (!response.ok) {\n\t\t\t\t<span class=\"hljs-keyword\">throw<\/span> data;\n\t\t\t}\n\n\t\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t\t<span class=\"hljs-attr\">props<\/span>: {\n\t\t\t\t\t<span class=\"hljs-attr\">video<\/span>: data.result\n\t\t\t\t}\n\t\t\t};\n\t\t} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\t\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t\t<span class=\"hljs-attr\">status<\/span>: error?.statusCode ?? <span class=\"hljs-number\">400<\/span>,\n\t\t\t\t<span class=\"hljs-attr\">error<\/span>: error?.message ?? <span class=\"hljs-string\">'Something went wrong'<\/span>\n\t\t\t};\n\t\t}\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">import<\/span> { goto } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'$app\/navigation'<\/span>;\n\n\t<span class=\"hljs-keyword\">let<\/span> isLoading = <span class=\"hljs-literal\">false<\/span>;\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> video;\n\n\t<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">deleteVideo<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\t\t<span class=\"hljs-keyword\">try<\/span> {\n\t\t\tisLoading = <span class=\"hljs-literal\">true<\/span>;\n\t\t\t<span class=\"hljs-keyword\">const<\/span> response = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">`\/api\/videos\/<span class=\"hljs-subst\">${video.public_id}<\/span>`<\/span>, {\n\t\t\t\t<span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'DELETE'<\/span>\n\t\t\t});\n\n\t\t\t<span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> response.json();\n\n\t\t\t<span class=\"hljs-keyword\">if<\/span> (!response.ok) {\n\t\t\t\t<span class=\"hljs-keyword\">throw<\/span> data;\n\t\t\t}\n\n\t\t\tgoto(<span class=\"hljs-string\">'\/videos'<\/span>, { <span class=\"hljs-attr\">replaceState<\/span>: <span class=\"hljs-literal\">true<\/span> });\n\t\t} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\t\t\t<span class=\"hljs-built_in\">console<\/span>.error(error);\n\t\t} <span class=\"hljs-keyword\">finally<\/span> {\n\t\t\tisLoading = <span class=\"hljs-literal\">false<\/span>;\n\t\t}\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"wrapper\"<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video\"<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{video.secure_url}<\/span> <span class=\"hljs-attr\">controls<\/span>&gt;<\/span>\n\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">track<\/span> <span class=\"hljs-attr\">kind<\/span>=<span class=\"hljs-string\">\"captions\"<\/span> \/&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"actions\"<\/span>&gt;<\/span>\n\t\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">on:click<\/span>|<span class=\"hljs-attr\">preventDefault<\/span>=<span class=\"hljs-string\">{deleteVideo}<\/span> <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{isLoading}<\/span>&gt;<\/span>Delete<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> {\n\t\t<span class=\"hljs-attribute\">min-width<\/span>: <span class=\"hljs-number\">100vh<\/span>;\n\t\t<span class=\"hljs-attribute\">display<\/span>: flex;\n\t\t<span class=\"hljs-attribute\">justify-content<\/span>: center;\n\t\t<span class=\"hljs-attribute\">align-items<\/span>: center;\n\t}\n\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.video<\/span> {\n\t\t<span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">80%<\/span>;\n\t}\n\n\t<span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.wrapper<\/span> <span class=\"hljs-selector-tag\">div<\/span><span class=\"hljs-selector-class\">.video<\/span> <span class=\"hljs-selector-tag\">video<\/span> {\n\t\t<span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n\t\t<span class=\"hljs-attribute\">object-fit<\/span>: fill;\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s talk about the first script tag. Note that this script tag is marked with <code>context=&quot;module&quot;<\/code>, this is because it\u2019s supposed to run before the component is rendered. If you\u2019ve used Next.js before, you probably know about <code>getStaticProps<\/code> or <code>getServerSideProps<\/code>. The <code>load<\/code> function that is used inside this script tag is very similar to Next.js <code>getStaticProps<\/code> or <code>getServerSideProps<\/code>. One difference is that in SvelteKit, the method runs on both the server and the client. Have a read of <a href=\"https:\/\/kit.svelte.dev\/docs#loading\">these docs<\/a> to avoid some common pitfalls. Since the load function also runs on the client, avoid accessing sensitive environment variables here.<\/p>\n<p>The <code>load<\/code> function, in this case, makes a GET request to the <code>\/api\/videos\/:id<\/code> endpoint. This returns the video with the specified ID. For the component, we have also have a <code>deleteVideo<\/code> function which makes a DELETE request to <code>\/api\/videos\/:id<\/code> and deletes the video with the specified ID from cloudinary. For the component body, we just have a video element that shows the video to the user.<\/p>\n<hr \/>\n<p>Good news! \ud83d\ude03 You made it to the end \ud83e\udd73. You can now run your application and try it out.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm run dev -- --open\n<\/code><\/span><\/pre>\n<blockquote>\n<p>Remember that this is a simple implementation for demonstration purposes. You can make a few optimizations for a production environment. Also, keep in mind that SvelteKit is still early in development. Issues such as native file upload are being sorted out and might be ready with the first stable version.<\/p>\n<\/blockquote>\n<h2>Codesandbox<\/h2>\n<p>The final project can be viewed on <a href=\"https:\/\/codesandbox.io\/s\/cctv-video-effect-6fl9r\">Codesandbox<\/a>.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/cctv-video-effect-6fl9r?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"cctv-video-effect\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><p>Thank you for your time. You can find the full source code on my <a href=\"https:\/\/github.com\/musebe\/cctv-video-effects\">Github<\/a>.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28424,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,382,376,371,303],"class_list":["post-28423","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-player-video","tag-svelte","tag-under-review","tag-video"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Creating CCVT Video Effect<\/title>\n<meta name=\"description\" content=\"Apply the CCTV grayscale and noisy effect to any video using Cloudinary and Svelte.js\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Creating CCVT Video Effect\" \/>\n<meta property=\"og:description\" content=\"Apply the CCTV grayscale and noisy effect to any video using Cloudinary and Svelte.js\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-23T22:05:54+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"650\" \/>\n\t<meta property=\"og:image:height\" content=\"417\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Creating CCVT Video Effect\",\"datePublished\":\"2022-03-23T22:05:54+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/\"},\"wordCount\":4,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Player Video\",\"Svelte\",\"Under Review\",\"Video\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/\",\"name\":\"Creating CCVT Video Effect\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA\",\"datePublished\":\"2022-03-23T22:05:54+00:00\",\"description\":\"Apply the CCTV grayscale and noisy effect to any video using Cloudinary and Svelte.js\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA\",\"width\":650,\"height\":417},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Creating CCVT Video Effect\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Creating CCVT Video Effect","description":"Apply the CCTV grayscale and noisy effect to any video using Cloudinary and Svelte.js","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/","og_locale":"en_US","og_type":"article","og_title":"Creating CCVT Video Effect","og_description":"Apply the CCTV grayscale and noisy effect to any video using Cloudinary and Svelte.js","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-23T22:05:54+00:00","og_image":[{"width":650,"height":417,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/"},"author":{"name":"","@id":""},"headline":"Creating CCVT Video Effect","datePublished":"2022-03-23T22:05:54+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/"},"wordCount":4,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA","keywords":["Guest Post","Player Video","Svelte","Under Review","Video"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/","name":"Creating CCVT Video Effect","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA","datePublished":"2022-03-23T22:05:54+00:00","description":"Apply the CCTV grayscale and noisy effect to any video using Cloudinary and Svelte.js","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA","width":650,"height":417},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/cctv-video-effect-using-cloudinary-and-svelte-kit\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Creating CCVT Video Effect"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924540\/Web_Assets\/blog\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21\/63599dbe551c27614bdd2d3cc9fddf224aa51e9c-650x417-1_284244ba21.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28423","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28423"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28423\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28424"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}