Как создать REST API в Scala с помощью Play Framework

Обзор

В предыдущих блогах я обсуждал игровой фреймворк, теперь мы можем перейти к другим темам, посвященным игре.

Для создания простых REST API в стиле CRUD на Scala хорошим решением является Play Framework. У него несложный API, который не требует от нас написания слишком большого количества кода.

В этом блоге мы собираемся создать REST API на Scala с помощью Play. Мы будем использовать JSON в качестве формата данных и рассмотрим несколько методов HTTP и коды состояния.

Что мы строим?

В качестве нашего примера мы создадим приложение со списком студентов. Вместо того, чтобы использовать базу данных, мы будем хранить элементы списка учащихся в памяти.

Приложение будет предоставлять несколько конечных точек, и мы будем создавать его небольшими поэтапными шагами.

Мы также рассмотрим, как запускать и тестировать наше приложение по мере его расширения.

Настройка проекта

Откройте терминал.

Перейдите в каталоги (cd) к папке, которая будет содержать папку проекта.

Выполните следующую команду и ответьте на запросы, чтобы создать новый шаблон проекта.

$ sbt новый playframework/play-scala-seed.g8

Это создает новый проект с одним контроллером (в  каталоге app/controllers  ), двумя файлами HTML (в  каталоге app/views  ) и базовой конфигурацией (в  каталоге conf  ).

Поскольку они нам не нужны, удалим   файлы HomeController.scalaindex.scala.html и  main.scala.html . Давайте также удалим существующее содержимое файла  маршрутов  .

Первая конечная точка REST

Создать контроллер

Во-первых, мы  создаем новый класс контроллера  в  каталоге app/controllers  .

@Singleton
class HomeController @Inject()(val controllerComponents: ControllerComponents)
extends BaseController {
}

Новый класс расширяет  BaseController  и имеет совместимый с ним конструктор.

Мы использовали  аннотацию @Inject  , чтобы заставить Play Framework автоматически передавать требуемые зависимости классов. И мы пометили класс как  @Singleton  , чтобы фреймворк создал только один экземпляр. Это означает, что он будет повторно использовать его для каждого запроса.

Возврат товаров

Теперь мы собираемся вернуть весь список студентов. Давайте определим модель данных, создадим коллекцию задач в памяти и изменим  HomeController  , чтобы он возвращал объекты JSON.

Определите модель

Во-первых, мы  создаем новый класс в   каталоге app/models :

case class Student(id: Int, address: String, name: String)

Список в памяти

Теперь мы определяем список задач в  классе HomeController   . Поскольку этот список будет изменен, нам понадобится  пакет mutable  collections:

class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {

  val studentList = new mutable.ListBuffer[Student]()
  studentList += Student(1,"Delhi","Mayank")
  studentList += Student(2,"Mathura","Yashika")

Чтобы облегчить наше тестирование, мы добавили в этот список пару жестко закодированных значений, которые будут доступны при запуске.

Форматировщик JSON

Далее давайте  создадим средство форматирования JSON, которое преобразует объект Studentlist в JSON . Начнем с импорта библиотеки JSON:

import play.api.libs.json._

После этого мы создаем средство форматирования JSON внутри  класса HomeController  :

implicit val studentListJson = Json.format[Student]
 

Мы делаем его неявным полем, чтобы не передавать его в  функцию Json.toJson  постоянно.

Условная логика в   функции getAll

Теперь у нас есть некоторые данные для возврата, давайте  изменим нашу  функцию getAll  , чтобы она возвращала  код состояния NoContent  только тогда, когда список пуст . В противном случае он должен вернуть элементы списка, преобразованные в JSON:

def getAll(): Action[AnyContent] = Action {
    if (studentList.isEmpty) NoContent else Ok(Json.toJson(studentList))
  }

Тестирование

Давайте проверим конечную точку GET:

$ localhost:9000

[
    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    },
    {
        "id": 2,
        "address": "Mathura",
        "name": "Yashika"
    }
]

Возврат одного товара

REST API также должен поддерживать  извлечение отдельных элементов с помощью параметра пути . Мы хотим иметь возможность делать что-то вроде:

$ curl localhost:9000/hello/1

Это должно вернуть элемент или  NotFound ,  если идентификатор неизвестен. Давайте это реализуем.

Добавление параметра к маршруту

Во-первых, мы определяем новую конечную точку в  файле маршрутов  :

ПОЛУЧИТЬ /hello/ :studentId                 controllers.HomeController.getById( studentId :Int)

Обозначение  /hello/:studentId означает, что Play Framework должен захватить все, что следует за  /hello/ префиксом, и присвоить его переменной  studentId . После этого Play вызывает  getById функцию и передает ее  studentId в качестве первого параметра.

Поскольку мы указали тип параметра, он автоматически преобразует текст в число или возвращает BadRequest,  если  параметр не является числом.

Поиск соответствующего элемента

В HomeController  добавим  метод getById  :

def getById(studentId:Int) : Action[AnyContent] = Action {
    val stdId = studentList.find(_.id == studentId)
    stdId match {
      case Some(value) => Ok(Json.toJson(value))
      case None => NotFound
    }
  }

Наш метод получает  параметр itemId  и пытается найти элемент списка учащихся с таким же идентификатором.

Мы используем  функцию поиска  , которая возвращает экземпляр класса  Option  . Итак, мы также используем сопоставление с образцом, чтобы отличить пустую  опцию  от  опции  со значением.

Когда элемент присутствует в списке учащихся, он преобразуется в JSON, возвращаемый в  ответе OK  . В противном случае   возвращается NotFound , вызывая HTTP 404.

Тестирование

Теперь мы можем попытаться получить найденный предмет:

$ localhost:9000/hello/1

    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    }

Или предмет, который не является:

$ localhost:9000/hello/999

204 No Content.

Методы PUT и DELETE

Play Framework обрабатывает все методы HTTP, поэтому, когда мы хотим использовать PUT или DELETE, нам нужно настроить их в  файле маршрутов  . Например, мы можем определить конечные точки, которые помечают элемент как завершенный и удаляют завершенные элементы:

PUT     /hello/:id                       controllers.HomeController.markAsDone(id:Int)
DELETE  /hello/done/:id                  controllers.HomeController.deleteAllDone(id:Int)

Добавление новой задачи

Наконец, наша реализация должна добавить новую задачу, когда мы  отправляем запрос POST  , содержащий новый элемент:

Обратите внимание, что мы должны указать только описание. Наше приложение сгенерирует  идентификатор  и начальный статус.

Конечная точка POST в   файле маршрутов

Во-первых, давайте укажем новую конечную точку в  файле маршрутов  :

POST /hello/addItem controllers.HomeController.addNewItem

Объект передачи данных

Теперь нам нужно добавить новый класс в  каталог app/models  . Создаем новый объект передачи данных (DTO), который содержит  поле описания  :

case class NewStudentItem(address:String , name:String)

Чтение объекта JSON

В  HomeController нам нужен форматировщик JSON для этого нового класса:

implicit val newStudentItem = Json.format[NewStudentItem]

Давайте также определим метод для  создания  объектов NewStudentListItem  из входных данных JSON :

В нашем методе  content.asJson анализируется данный объект JSON и возвращается  OptionМы получили бы действительный объект только в том случае, если бы десериализация прошла успешно.

Если вызывающая сторона отправила нам контент, который не может быть десериализован, поскольку  NewStudentItem  или  Content-Type  не был  application/json , вместо этого мы получаем  None  .

Добавление нового элемента

Теперь добавим следующий код в конец  addNewItem . Это либо  сохранит новый объект и вернет HTTP  Created  , либо ответит  BadRequest :

def addNewItem(): Action[JsValue] = Action(parse.json) { implicit request =>
      request.body.validate[NewStudentItem].asOpt
        .fold{
         BadRequest("No item added")
        }
    {
      response =>
      val nextId = studentList.map(_.id).max +1
        val newItemAdded = Student(nextId,response.address,response.name)
        studentList += newItemAdded
        Ok(Json.toJson(studentList))
    }
    }

Тестирование

Давайте протестируем добавление нового элемента в список: POST-запрос

$ локальный: 9000/привет/добавитьItem

{
    "address": "Mumbai",
    "name": "Kamal"
}

В ответ мы должны увидеть  код состояния Created  и новый элемент в теле ответа. Кроме того, чтобы убедиться, что элемент был добавлен в список, мы можем снова получить все элементы:

$ localhost:9000/hello/addItem

[
    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    },
    {
        "id": 2,
        "address": "Mathura",
        "name": "Yashika"
    },
    {
        "id": 3,
        "address": "Mumbai",
        "name": "Kamal"
    }
]

На этот раз массив JSON должен содержать три объекта, включая только что добавленный.

Следует  отметить, что крайне важно указать   заголовок Content-Type . В противном случае Play Framework считывает данные как   и не может преобразовать их в объект JSON.application/x-www-form-urlencoded

Заключение

В этой статье мы реализовали REST API в Play Framework с помощью Scala.

Во-первых, мы инициализировали проект и определили наш первый маршрут и класс контроллера. Затем мы определили объекты DTO и преобразовали их в формат JSON и обратно.

Мы также рассмотрели, как использовать  curl  для проверки правильности работы нашего кода.

Оригинальный источник статьи: https://blog.knoldus.com/

#scala #rest #api #play #framework 

Как создать REST API в Scala с помощью Play Framework
津田  淳

津田 淳

1680863701

如何使用 Play Framework 在 Scala 中构建 REST API

概述

在之前的博客中,我讨论了有关游戏框架的内容,现在让我们转到有关游戏的更多主题。

要在 Scala 中构建简单的、CRUD 风格的 REST API,Play Framework 是一个很好的解决方案。它有一个简单的 API,不需要我们编写太多代码。

在此博客中,我们将使用 Scala 和 Play 构建一个 REST API。我们将使用 JSON 作为数据格式并查看多个 HTTP 方法和状态代码。

我们建造什么?

作为我们的示例,我们将构建一个学生列表应用程序。我们不使用数据库,而是将学生列表项存储在内存中。

该应用程序将提供多个端点,我们将逐步构建它。

我们还将了解如何在我们开发应用程序时运行和测试它。

设置项目

打开一个终端。

导航到目录 (cd) 到将包含项目文件夹的文件夹。

运行以下命令,根据提示新建一个项目模板

$ sbt 新游戏框架/play-scala-seed.g8

这将创建一个新项目,其中包含一个控制器(在 app/controllers 目录中)、两个 HTML 文件(在 app/views 目录中)和一个基本配置(在 conf 目录中)。

因为我们不需要它们,所以让我们删除 HomeController.scala、  index.scala.html和 main.scala.html 文件。让我们也删除路由文件的现有内容  。

第一个 REST 端点

创建控制器

首先,我们  在 app/controllers目录中创建一个新的控制器类 。

@Singleton
class HomeController @Inject()(val controllerComponents: ControllerComponents)
extends BaseController {
}

新类扩展了 BaseController 并具有与其兼容的构造函数。

我们使用 @Inject 注释指示Play Framework 自动传递所需的类依赖项。并且,我们将该类标记为 @Singleton ,这样框架将只创建一个实例。这意味着它将为每个请求重用它。

退货

现在,我们要返回整个学生列表。让我们定义数据模型,创建内存中的任务集合,并修改 HomeController  返回 JSON 对象。

定义模型

首先,我们 在app/models 目录中创建一个新类 

case class Student(id: Int, address: String, name: String)

内存列表

现在,我们在HomeController类中定义任务列表   。由于此列表将被修改,我们需要 可变 集合包:

class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {

  val studentList = new mutable.ListBuffer[Student]()
  studentList += Student(1,"Delhi","Mayank")
  studentList += Student(2,"Mathura","Yashika")

为了帮助我们进行测试,我们在此列表中添加了几个硬编码值,以便在启动时可用。

JSON格式化程序

接下来,让我们 创建将 Studentlist 对象转换为 JSON 的 JSON 格式化程序。我们首先导入 JSON 库:

import play.api.libs.json._

之后,我们在 HomeController 类中创建 JSON 格式化程序:

implicit val studentListJson = Json.format[Student]
 

我们将其设为隐式字段,以避免必须  始终将其传递给Json.toJson函数。

getAll 函数中的条件逻辑 

现在我们有一些数据要返回,让我们 更改 getAll函数以 仅在列表为空时 返回 NoContent状态代码。否则,它应该返回转换为 JSON 的列表项:

def getAll(): Action[AnyContent] = Action {
    if (studentList.isEmpty) NoContent else Ok(Json.toJson(studentList))
  }

测试

让我们测试 GET 端点:

$ localhost:9000

[
    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    },
    {
        "id": 2,
        "address": "Mathura",
        "name": "Yashika"
    }
]

退回一件商品

REST API 还应该支持 通过路径参数检索单个项目。我们希望能够做类似的事情:

$ curl localhost:9000/hello/1

这应该返回该项目,  如果 ID 未知,则返回 NotFound 。让我们来实现它。

向路由添加参数

首先,我们在路由文件中定义一个新端点  :

GET /你好/ :studentId                 controllers.HomeController.getById( studentId :Int)

符号 /hello/:studentId 意味着 Play Framework 应该捕获 /hello/ 前缀后的所有内容并将其分配给 studentId 变量。之后,Play 调用该 getById 函数并将 作为其第一个参数传递 studentId 。

因为我们指定了参数类型,所以它会自动将文本转换为数字,或者  如果参数不是数字则返回BadRequest 。

寻找匹配元素

HomeController 中, 让我们添加 getById 方法:

def getById(studentId:Int) : Action[AnyContent] = Action {
    val stdId = studentList.find(_.id == studentId)
    stdId match {
      case Some(value) => Ok(Json.toJson(value))
      case None => NotFound
    }
  }

我们的方法获取 itemId 参数并尝试查找具有相同 id 的学生列表项。

我们正在使用 find函数,它返回Option类 的一个实例  。因此,我们还使用模式匹配来区分空 选项 和  有值选项。

当该项目出现在学生列表中时,它会转换为 JSON 并在 OK 响应中返回。否则, 返回NotFound—— 导致 HTTP 404。

测试

现在,我们可以尝试获取找到的项目:

$ localhost:9000/hello/1

    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    }

或者不是的项目:

$ localhost:9000/hello/999

204 No Content.

PUT 和 DELETE 方法

Play Framework 处理所有的 HTTP 方法,所以当我们想使用 PUT 或 DELETE 时,我们需要在 路由 文件中配置它们。例如,我们可以定义将项目标记为已完成并删除已完成项目的端点:

PUT     /hello/:id                       controllers.HomeController.markAsDone(id:Int)
DELETE  /hello/done/:id                  controllers.HomeController.deleteAllDone(id:Int)

添加新任务

 最后,当我们发送包含新项目的POST 请求时,我们的实现应该添加一个新任务 :

请注意,我们必须仅指定描述。我们的应用程序将生成 id 和初始状态。

路由 文件中的 POST 端点 

首先,让我们在路由文件中指定新端点  :

POST /hello/addItem controllers.HomeController.addNewItem

数据传输对象

现在,我们需要向app/models目录添加一个新类  。我们创建一个新的数据传输对象(DTO),其中包含 描述 字段:

case class NewStudentItem(address:String , name:String)

读取 JSON 对象

在 HomeController中,我们需要一个用于该新类的 JSON 格式化程序:

implicit val newStudentItem = Json.format[NewStudentItem]

让我们还定义一个方法来  从 JSON 输入创建 NewStudentListItem对象:

在我们的方法中, content.asJson 解析给定的 JSON 对象并返回一个 Option。 只有反序列化成功,我们才会得到一个有效的对象。

如果调用者向我们发送了无法反序列化为 NewStudentItem 或 Content-Type 不是 application/json 的内容,我们最终将返回 None  。

添加新项目

现在,让我们将以下代码添加到addNewItem的末尾 。这将 存储新对象并返回 HTTP  Created 或响应 BadRequest

def addNewItem(): Action[JsValue] = Action(parse.json) { implicit request =>
      request.body.validate[NewStudentItem].asOpt
        .fold{
         BadRequest("No item added")
        }
    {
      response =>
      val nextId = studentList.map(_.id).max +1
        val newItemAdded = Student(nextId,response.address,response.name)
        studentList += newItemAdded
        Ok(Json.toJson(studentList))
    }
    }

测试

让我们测试向列表中添加一个新项目:POST 请求

$ localhost:9000/你好/addItem

{
    "address": "Mumbai",
    "name": "Kamal"
}

作为响应,我们应该  在响应正文中看到Created状态代码和新项目。此外,为了验证该项目是否已添加到列表中,我们可以再次检索所有项目:

$ localhost:9000/hello/addItem

[
    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    },
    {
        "id": 2,
        "address": "Mathura",
        "name": "Yashika"
    },
    {
        "id": 3,
        "address": "Mumbai",
        "name": "Kamal"
    }
]

这次,JSON 数组应该包含三个对象,包括新添加的对象。

我们应该 注意到,指定 Content-Type  header是至关重要的。否则,Play Framework 读取数据 application/x-www-form-urlencoded 并无法将其转换为 JSON 对象。

结论

在本文中,我们使用 Scala 在 Play Framework 中实现了一个 REST API。

首先,我们初始化项目并定义我们的第一个路由和控制器类。然后我们定义了 DTO 对象并将它们转换为 JSON 格式。

我们还研究了如何使用 curl 来验证我们的代码是否正常工作。

文章原文出处:https: //blog.knoldus.com/

#scala #rest #api #play #framework 

如何使用 Play Framework 在 Scala 中构建 REST API
Rocio  O'Keefe

Rocio O'Keefe

1680859936

How to Build REST API in Scala with Play Framework

Overview

In earlier blogs I discussed about play framework now lets we move to further topics on play.

For building simple, CRUD-style REST APIs in Scala, the Play Framework is a good solution. It has an uncomplicated API that doesn’t require us to write too much code.

In this blog, we’re going to build a REST API in Scala with Play. We’ll use JSON as the data format and look at multiple HTTP methods and status codes.

What we build ?

As our example, we’ll build a student list application. Rather than use a database, we’ll store the student list items in memory.

The application will provide several endpoints, and we’ll build it in small, incremental steps.

We’ll also look at how to run and test our application as we grow it.

Setup the Project

Open a terminal.

Navigate to directories (cd) to the folder that will contain the project folder.

Run the following command and respond to the prompts to create a new project template

$ sbt new playframework/play-scala-seed.g8

This creates a new project with one controller (in the app/controllers directory), two HTML files (in the app/views directory), and a basic configuration (in the conf directory).

As we don’t need them, let’s remove HomeController.scalaindex.scala.html, and main.scala.html files. Let’s also remove the existing content of the routes file.

The First REST Endpoint

Create a Controller

First, we create a new controller class in the app/controllers directory.

@Singleton
class HomeController @Inject()(val controllerComponents: ControllerComponents)
extends BaseController {
}

The new class extends BaseController and has a constructor that’s compatible with it.

We’ve used the @Inject annotation to instruct the Play Framework to pass the required class dependencies automatically. And, we marked the class as a @Singleton so that the framework will create only one instance. This means it will reuse it for every request.

Returning Items

Now, we are going to return the whole student list. Let’s define the data model, create an in-memory collection of tasks, and modify the HomeController to return JSON objects.

Define the Model

First, we create a new class in the app/models directory:

case class Student(id: Int, address: String, name: String)

In-Memory List

Now, we define the list of tasks in the HomeController  class. As this list will be modified, we need the mutable collections package:

class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {

  val studentList = new mutable.ListBuffer[Student]()
  studentList += Student(1,"Delhi","Mayank")
  studentList += Student(2,"Mathura","Yashika")

To help with our testing, we’ve added a couple of hard-coded values in this list to be available from startup.

JSON Formatter

Next, let’s create the JSON formatter that converts the Studentlist object into JSON. We start by importing the JSON library:

import play.api.libs.json._

After that, we create the JSON formatter inside the HomeController class:

implicit val studentListJson = Json.format[Student]
 

We make it an implicit field to avoid having to pass it to the Json.toJson function all the time.

Conditional Logic in the getAll Function

Now we have some data to return, let’s change our getAll function to return the NoContent status code only when the list is empty. Otherwise, it should return the list items converted to JSON:

def getAll(): Action[AnyContent] = Action {
    if (studentList.isEmpty) NoContent else Ok(Json.toJson(studentList))
  }

Testing

Let’s test the GET endpoint:

$ localhost:9000

[
    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    },
    {
        "id": 2,
        "address": "Mathura",
        "name": "Yashika"
    }
]

Returning One Item

A REST API should also support retrieving individual items via a path parameter. We want to be able to do something like:

$ curl localhost:9000/hello/1

This should return the item, or NotFound if the ID is unknown. Let’s implement that.

Adding a Parameter to the Route

First, we define a new endpoint in the routes file:

GET     /hello/:studentId                controllers.HomeController.getById(studentId:Int)

The notation /hello/:studentId  means that the Play Framework should capture everything after the /hello/ prefix and assign it to the studentId variable. After that, Play calls the getById function and passes the studentId as its first parameter.

Because we have specified the parameter type, it automatically converts the text to a number or returns a BadRequest if the parameter is not a number.

Finding the Matching Element

In the HomeController, let’s add the getById method:

def getById(studentId:Int) : Action[AnyContent] = Action {
    val stdId = studentList.find(_.id == studentId)
    stdId match {
      case Some(value) => Ok(Json.toJson(value))
      case None => NotFound
    }
  }

Our method gets the itemId parameter and tries to find the student list item with the same id.

We’re using the find function, which returns an instance of the Option class. So, we also use pattern matching to distinguish between an empty Option and an Option with a value.

When the item is present in the student list, it’s converted into JSON returned in an OK response. Otherwise, NotFound is returned – causing an HTTP 404.

Testing

Now, we can try to get an item that is found:

$ localhost:9000/hello/1

    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    }

Or an item that isn’t:

$ localhost:9000/hello/999

204 No Content.

PUT and DELETE Methods

The Play Framework handles all HTTP methods, so when we want to use PUT or DELETE, we need to configure them in the routes file. For example, we can define endpoints that mark an item as completed and remove completed items:

PUT     /hello/:id                       controllers.HomeController.markAsDone(id:Int)
DELETE  /hello/done/:id                  controllers.HomeController.deleteAllDone(id:Int)

Adding a New Task

Finally, our implementation should add a new task when we send a POST request containing a new item:

Note that we must specify only the description. Our application will generate the id and the initial status.

POST Endpoint in the routes File

First, let’s specify the new endpoint in the routes file:

POST     /hello/addItem                  controllers.HomeController.addNewItem

Data Transfer Object

Now, we need to add a new class to the app/models directory. We create a new data transfer object (DTO), which contains the description field:

case class NewStudentItem(address:String , name:String)

Reading the JSON Object

In the HomeController, we need a JSON formatter for that new class:

implicit val newStudentItem = Json.format[NewStudentItem]

Let’s also define a method to create NewStudentListItem objects from the JSON input:

In our method, content.asJson parses the given JSON object and returns an OptionWe would get a valid object only if the deserialization were successful.

If the caller has sent us content that cannot be deserialized as a NewStudentItem or Content-Type was not application/json, we end up with a None instead.

Adding a New Item

Now, let’s add the following code to the end of addNewItem. This will either store the new object and return HTTP Created or respond with BadRequest:

def addNewItem(): Action[JsValue] = Action(parse.json) { implicit request =>
      request.body.validate[NewStudentItem].asOpt
        .fold{
         BadRequest("No item added")
        }
    {
      response =>
      val nextId = studentList.map(_.id).max +1
        val newItemAdded = Student(nextId,response.address,response.name)
        studentList += newItemAdded
        Ok(Json.toJson(studentList))
    }
    }

Testing

Let’s test adding a new item to the list: POST request

$ localhost:9000/hello/addItem

{
    "address": "Mumbai",
    "name": "Kamal"
}

In response, we should see the Created status code and the new item in the response body. Additionally, to verify that the item was added to the list, we can retrieve all items again:

$ localhost:9000/hello/addItem

[
    {
        "id": 1,
        "address": "Delhi",
        "name": "Mayank"
    },
    {
        "id": 2,
        "address": "Mathura",
        "name": "Yashika"
    },
    {
        "id": 3,
        "address": "Mumbai",
        "name": "Kamal"
    }
]

This time, the JSON array should contain three objects, including the newly added one.

We should note that it’s crucial to specify the Content-Type header. Otherwise, Play Framework reads the data as application/x-www-form-urlencoded and fails to convert it into a JSON object.

Conclusion

In this article, we implemented a REST API in the Play Framework using Scala.

First, we initialized the project and defined our first route and controller class. Then we defined DTO objects and converted them in and out of JSON format.

We have also looked at how to use curl to verify that our code works correctly.

Original article source at: https://blog.knoldus.com/

#scala #rest #api #play #framework 

How to Build REST API in Scala with Play Framework

ian hardy

1678348469

Create a custom YouTube player using jQuery

Introduction

YouTube is one of the most popular video-sharing platforms, with millions of users worldwide. As such, it has become a critical component of many businesses' marketing strategies, enabling them to reach a broader audience and engage with customers on a more personal level. However, while YouTube provides a wealth of features and functionalities, businesses may still desire more control over the viewing experience. One way to achieve this is by creating a custom YouTube player using jQuery. In this blog, we will discuss the technical aspects of creating a custom YouTube player using jQuery, its benefits, and how CronJ can help.

What is jQuery?

jQuery is a popular JavaScript library that simplifies HTML document traversing, event handling, and animating. It was created by John Resig in 2006 and has become one of the most widely used JavaScript libraries in web development. jQuery allows developers to write less code and achieve more functionality, making it an essential tool for many web developers.

jQuery provides a range of features that can be used to manipulate HTML and CSS elements on a web page. It includes a set of functions that allow developers to easily perform tasks such as selecting and manipulating HTML elements, handling events, animating elements, and making AJAX requests.

One of the primary benefits of jQuery is that it simplifies the process of writing cross-browser compatible code. This is because jQuery abstracts away many of the differences between browsers, providing a consistent and easy-to-use API for developers. With jQuery, developers can write code that works across all modern browsers without having to worry about browser-specific quirks and differences.

Overall, jQuery is a powerful and widely used tool for web developers. Its ease of use, cross-browser compatibility, and wide range of features make it an essential tool for building modern web applications.

How to custom YouTube player using jQuery?

Creating a custom YouTube player using jQuery can be achieved by using the YouTube Iframe API, which provides a way to interact with YouTube videos and playlists through an HTML iframe. Here are the steps to create a custom YouTube player using jQuery:

  1. Add the YouTube Iframe API script to your HTML page:

<script src="https://www.youtube.com/iframe_api"></script>

2. Create an HTML container element for the YouTube video player:

<div id="player"></div>

3. In your jQuery code, create a player variable and configure the player settings:

var player;

function onYouTubeIframeAPIReady() {
 player = new YT.Player('player', {
   height: '360',
   width: '640',
   videoId: 'VIDEO_ID',
   playerVars: {
     'autoplay': 0,
     'controls': 0,
     'showinfo': 0
   },
   events: {
     'onReady': onPlayerReady,
     'onStateChange': onPlayerStateChange
   }
 });
}
 

In the code above, height and width specify the dimensions of the video player, videoId is the ID of the YouTube video to play, and playerVars specifies the player options, such as disabling autoplay and video controls. The events parameter specifies the player event handlers, which we will define in the next steps.

4. Define the onPlayerReady and onPlayerStateChange event handlers. For example, to start playing the video when the player is ready, you can add the following code:

function onPlayerReady(event) {
 event.target.playVideo();
}

To loop the video when it ends, you can add the following code to the onPlayerStateChange event handler:

function onPlayerStateChange(event) {
 if (event.data == YT.PlayerState.ENDED) {
   player.seekTo(0);
   player.playVideo();
 }
}

5. You can also add custom controls to the video player using jQuery. For example, to add a "play" button that starts the video, you can add the following code to your jQuery script:

$('#play-button').on('click', function() {
 player.playVideo();
});

In this example, #play-button is the ID of the HTML element that triggers the play action.

6. Finally, you can style the video player and controls using CSS. For example, to position the player in the center of the page, you can add the following style:

#player {
 display: block;
 margin: 0 auto;
}

These are the basic steps to create a jquery youtube player. With additional JavaScript and jQuery code, you can further customize the player and add features like playlists, subtitles, and more.

Technical Aspects

To create a custom YouTube player using jQuery, several technical aspects need to be considered. These include:

The YouTube API: The YouTube API is the primary means of interacting with the YouTube platform programmatically. It allows developers to access various YouTube features, such as search, uploads, and player functionality. By utilizing the YouTube API, developers can customize the player's appearance and functionality, as well as access valuable analytics data.

jQuery: jQuery is a popular JavaScript library that simplifies HTML document traversal and manipulation, as well as event handling, animation, and AJAX interactions. It provides a straightforward syntax for selecting HTML elements and modifying their properties, making it an ideal choice for creating a custom YouTube player.

HTML and CSS: HTML and CSS are essential for creating the layout and styling of the custom player. By leveraging HTML and CSS, developers can create a custom player that fits seamlessly into their website's design and branding.

Benefits

There are several benefits to creating a custom YouTube player using jQuery. These include:

Branding: Creating a custom player allows businesses to showcase their branding, making it easier for viewers to identify their content and associate it with their brand. This branding can include elements such as logos, colors, and custom player controls.

Customization: Customizing the player's appearance and functionality allows businesses to provide a more immersive and engaging viewing experience. This customization can include features such as custom thumbnails, autoplay, and video looping.

Analytics: The YouTube API provides access to valuable analytics data, enabling businesses to gain insights into their viewers' behavior and engagement with their content. By leveraging this data, businesses can optimize their content strategy to improve their ROI.

Limitations to creating a custom YouTube player using jQuery

While creating a custom YouTube player using jQuery can be a great way to customize the player and add additional functionality, there are some limitations to consider.

YouTube API: YouTube provides an API that allows developers to interact with the player and customize its behavior. However, this API has some limitations, including rate limiting and quota restrictions. This means that if you are building a high-traffic site, you may need to pay for additional access to the API.

Cross-domain restrictions: The YouTube API enforces cross-domain restrictions that can prevent you from loading and manipulating the player from a different domain. This means that you may need to use workarounds such as JSONP or CORS to access the API from a different domain.

Browser compatibility: While jQuery provides a simplified API for manipulating the DOM and handling events, there are still differences between browsers that can cause compatibility issues. This means that you may need to write browser-specific code or use polyfills to ensure that your custom YouTube player works across all modern browsers.

Performance: Customizing the YouTube player using jQuery can add additional overhead to the page, which can affect performance. To minimize this impact, it is important to use efficient code and minimize the number of requests and interactions with the YouTube API.

Legal issues: It is important to be aware of the legal issues surrounding the use of YouTube videos and the YouTube API. For example, YouTube's terms of service prohibit the use of the API for commercial purposes without prior approval.

Overall, while creating a custom YouTube player using jQuery can be a powerful way to add additional functionality and customization, it is important to be aware of these limitations and plan accordingly. By understanding these limitations and taking steps to mitigate them, you can create a custom YouTube player that meets your needs and provides a great user experience.

CronJ Expertise

As an expert in jQuery and web development, CronJ can provide customized solutions for creating a custom YouTube player that meets your specific needs. Our team of experienced developers can work with you to create a player that seamlessly integrates with your website's design and branding, while also providing the functionality and analytics data you need to achieve your business goals.

Conclusion

In conclusion, creating a custom YouTube player using jQuery is a powerful way for businesses to enhance their branding, customize the viewing experience, and gain valuable analytics data. By leveraging the YouTube API and jQuery, businesses can create a player that meets their specific needs, providing a more immersive and engaging viewing experience for their viewers. With CronJ's expertise in jQuery and web development, businesses can rest assured that their custom YouTube player will meet their needs and exceed their expectations.

Reference

1, https://www.jqueryscript.net/tags.php?/Youtube/

2. https://github.com/pupunzi/jquery.mb.YTPlayer

Create a custom YouTube player using jQuery

Record And Play Audio in JavaScript

Record And Play Audio in JavaScript

In this article, we will see how to record and play audio in javascript. Here, we will learn about how to record audio from a web page and play recorded audio. First, ask the user for microphone access to the browser and record the audio through the microphone and save the audio data chunks in form of binary values in an array when we play the audio then retrieve chuck data and start playing.

Also, we will use the getUserMedia() function. The MediaDevices.getUserMedia() method prompts the user for permission to use a media input which produces a MediaStream with tracks containing the requested types of media. That stream can include, for example, a video track, an audio track, and possibly other track types.

We will also use MediaRecorder() function. The MediaRecorder interface of the MediaStream Recording API provides functionality to easily record media. It is created using the MediaRecorder() constructor.

So, let's see how to record audio in javascript, how to record audio using jquery, getusermedia example, mediarecorder javascript example, and javascript record audio from web page.

Step 1: Start recording the audio

Step 2: While recording, store the audio data chunks

Step 3: Stop recording the audio

Step 4: Convert the audio data chunks to a single audio data blob

Step 5: Create a URL for that single audio data blob

Step 6: Play the audio

Example:

<!DOCTYPE html>
<html>
<head>
    <title>How To Record And Play Audio In JavaScript - Websolutionstuff</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>    
<style>
    body{
        margin:50px;
    }
</style>
<body class="text-center">
	<h4>How To Record And Play Audio In JavaScript - Websolutionstuff</h4>
    <p class="mt-5 mb-5">
        <button class="btn btn-dark" id="btnStart">START RECORDING</button>
        <button class="btn btn-dark" id="btnStop">STOP RECORDING</button>	
    </p>
<audio controls></audio>
<audio id="audioPlay" controls></audio>
</body>
</html>
<script>
	let audioIN = { audio: true };
	// audio is true, for recording

	// Access the permission for use
	// the microphone
	navigator.mediaDevices.getUserMedia(audioIN).then(function (mediaStreamObj) {

		// Connect the media stream to the
		// first audio element
		let audio = document.querySelector('audio');
		//returns the recorded audio via 'audio' tag

		// 'srcObject' is a property which
		// takes the media object
		// This is supported in the newer browsers
		if ("srcObject" in audio) {
		    audio.srcObject = mediaStreamObj;
		}
		else {
		audio.src = window.URL
			.createObjectURL(mediaStreamObj);
		}

		// It will play the audio
		audio.onloadedmetadata = function (ev) {

		// Play the audio in the 2nd audio
		// element what is being recorded
		audio.play();
		};

		// Start record
		let start = document.getElementById('btnStart');

		// Stop record
		let stop = document.getElementById('btnStop');

		// 2nd audio tag for play the audio
		let playAudio = document.getElementById('audioPlay');

		// This is the main thing to recorded
		// the audio 'MediaRecorder' API
		let mediaRecorder = new MediaRecorder(mediaStreamObj);
		// Pass the audio stream

		// Start event
		start.addEventListener('click', function (ev) {
		mediaRecorder.start();
		    console.log(mediaRecorder.state);
		})

		// Stop event
		stop.addEventListener('click', function (ev) {
		mediaRecorder.stop();
		    console.log(mediaRecorder.state);
		});

		// If audio data available then push
		// it to the chunk array
		mediaRecorder.ondataavailable = function (ev) {
		dataArray.push(ev.data);
		}

		// Chunk array to store the audio data
		let dataArray = [];

		// Convert the audio data in to blob
		// after stopping the recording
		mediaRecorder.onstop = function (ev) {

		// blob of type mp3
		let audioData = new Blob(dataArray,
					{ 'type': 'audio/mp3;' });
		
		// After fill up the chunk
		// array make it empty
		dataArray = [];

		// Creating audio url with reference
		// of created blob named 'audioData'
		let audioSrc = window.URL
			.createObjectURL(audioData);

		// Pass the audio url to the 2nd video tag
		playAudio.src = audioSrc;
		}
	})

	// If any error occurs then handles the error
	.catch(function (err) {
		console.log(err.name, err.message);
	});
</script>

Output:

how_to_record_and_play_audio_in_javascript_output

Original article source at: https://websolutionstuff.com/

#javascript #play #audio 

Record And Play Audio in JavaScript
Nigel  Uys

Nigel Uys

1671252300

How to Playing with Semantic Data and MarkLogic

In this blog, I will discuss the Semantic Data Model and its support in one of the enterprise NoSQL databases with an example.

What is a Data Model

Data models always come into the picture when we talk about any database and what type of data storage and query utility it provides. The data model defines the structure, as well as the relationships of data elements. Some of the popular data models that everyone must have heard of are the relational data model. Where data is kept in form of tables or relations.

What is Semantic Data Model

A semantic data model is about storing semantics (real meaning between two entities) in form of a specified format that tells about the relations between two entities. Consider the below two statements as the semantics of entities Author, Employee, Book, etc.

  • Clean Code is a Book.
  • Uncle Bob is the Author of “Clean Code”
  • Uncle Bob is an Employee of XCompany

If we represent it diagrammatically, It will look something like the below:

The magic of the Semantic model is that when we care about the semantics or the relations among the data, we are able to infer a few things which are not stored directly as information but true and inferred. For e.g. An employee can write a book, or an Employee has written a Book.

What has MarkLogic to do with Semantic Model

MarkLogic is one of the Database offering providing support to store and query the Semantic data. If you have not heard of this database before or installed it before, I found the documentation of MarkLogic very detailed which will give you a glimpse of introductory enlightenment of the Database. Likewise, If you want to install MarkLogic on Linux or ubuntu, you will find this blog very much helpful.

Starting with Experiment

I assume you have installed the MarkLogic and the server is running on your system. I am running a local cluster which will give you a start on localhost:8001/ and hopefully you would see an interface like the below:

MarkLogic Server Running on Local Cluster

Importing Semantic Data into MarkLogic

The data format here which I will be using for explanation is RDF triples. This is a format for Semantic Data Model. The data format will take the form of:

RDF Data Format.

For e.g. “Uncle Bob” has authored “Clean Code”.

For this blog, I will be using the same data set which is provided as part of a very detailed document from MarkLogic starting with Semantic Data. To check what is required before you can start hands-on, jump to the Pre-Requisites section.

To insert the triples on in the database, follow the simple steps below. I will be using

  • Open localhost:8000 (Query console in your browser)
  • Copy the below text into the query console and change the type of query to XQuery.

import module namespace sem = "http://marklogic.com/semantics"  at "/MarkLogic/semantics.xqy";   sem:rdf-insert(  (  sem:triple(    sem:iri("http://example.org/marklogic/people/Uncle_Bob"),    sem:iri("http://example.org/marklogic/predicate/authored"),    "Clean Code"    )  ,  sem:triple(    sem:iri("http://example.org/marklogic/people/Uncle_Bob"),    sem:iri("http://example.org/marklogic/predicate/livesOn"),    "Earth"    )  ) )

The above snippet, I have borrowed from the documentation as I mentioned before. Once it is written, hit the “Run” button and you would see a response there.

Inserting RDF Triples

Once the data is inserted, we can verify using the triple count. using the below function in another tab.

We have inserted 2 triples. In my case, It was three, you would see 2.

Querying RDF Data

As part of the above RDF data, we already established the below facts.

  • Uncle_Bob lives on Earth
  • Uncle_Bob authored Clean Code

Let us use the SPARQL query language to query the same question “Who lives on Earth”? . SPARQL is the query that is used to run on semantic data. Here you can find more about the SPARQL query structure in W3 documentation.

Original article source at: https://blog.knoldus.com/

#play #data #nosql #database 

How to Playing with Semantic Data and MarkLogic
Joshua Yates

Joshua Yates

1664183033

Create a Custom Music Player with HTML, CSS & JavaScript

In this tutorial, you'll learn how to create a custom music player with HTML, CSS and JavaScript.

The music player project might seem to be lengthy and complicated at first but I have divided the JavaScript code into 15 easy steps. You can easily create and customize the music player with these 15 steps.

  1. Create Initial References
  2. Create An Array For Song List
  3. Detect If It Is A Touch Device
  4. Format Time
  5. A Function To Set Song
  6. Function To Play Song
  7. Implement Function To Toggle Repeat Mode
  8. Function To Play Next Song
  9. Function To Pause Song
  10. Create Function To Play Previous Song
  11. Function To Toggle Shuffle Mode
  12. Adding Event Listener to Progress Bar
  13. Updating Progress Bar and Time
  14. Function To Create Playlist
  15. Function To Show & Hide Playlist

HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Custom Music Player</title>
    <!-- Font Awesome Icons -->
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"
      integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    />
    <!-- Google Fonts -->
    <link
      href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&family=Roboto+Mono&display=swap"
      rel="stylesheet"
    />
    <!-- Stylesheet -->
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="music-player">
      <button id="playlist">
        <i class="fa-solid fa-angle-down"></i>
      </button>
      <img id="song-image" src="make-me-move.jpg" />
      <div class="song-details">
        <p id="song-name">Make Me Move</p>
        <p id="song-artist">Culture Code</p>
      </div>
      <div class="player-options">
        <button id="shuffle">
          <i class="fa-solid fa-shuffle"></i>
        </button>
        <button id="prev">
          <i class="fa-solid fa-backward-step"></i>
        </button>
        <button id="play">
          <i class="fa-solid fa-play"></i>
        </button>
        <button id="pause" class="hide">
          <i class="fa-solid fa-pause"></i>
        </button>
        <button id="next">
          <i class="fa-solid fa-forward-step"></i>
        </button>
        <button id="repeat">
          <i class="fa-solid fa-repeat"></i>
        </button>
      </div>
      <audio id="audio" preload="metadata"></audio>
      <div id="progress-bar">
        <div id="current-progress"></div>
      </div>
      <div class="time-container">
        <span id="current-time">0:00</span>
        <span id="max-duration">0:00</span>
      </div>
      <div id="playlist-container" class="hide">
        <button id="close-button">
          <i class="fa-solid fa-xmark"></i>
        </button>
        <ul id="playlist-songs"></ul>
      </div>
    </div>
    <!-- Script -->
    <script src="script.js"></script>
  </body>
</html>

CSS:

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
body {
  height: 100vh;
  background: linear-gradient(to bottom, #2887e3 50%, #16191e 50%);
}
.music-player {
  font-size: 16px;
  width: 80vw;
  max-width: 25em;
  background-color: #ffffff;
  padding: 3em 1.8em;
  position: absolute;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
  border-radius: 0.5em;
  box-shadow: 0.6em 1.2em 3em rgba(0, 0, 0, 0.25);
}
img {
  width: 100%;
  margin-top: 1.25em;
}
#playlist {
  float: right;
}
.song-details {
  font-family: "Poppins", sans-serif;
  text-align: center;
}
.song-details #song-name {
  font-size: 1.3em;
  font-weight: 600;
  letter-spacing: 0.3px;
}
.song-details #song-artist {
  font-size: 0.8em;
}
.player-options {
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 0 1.25em;
  margin: 1.25em 0 0.6em 0;
}
.music-player button {
  border: none;
  background-color: transparent;
}
#play,
#pause {
  height: 2.5em;
  width: 2.5em;
  font-size: 1.8em;
  background-color: #2887e3;
  color: #ffffff;
  border-radius: 50%;
}
#prev,
#next {
  color: #16191e;
  font-size: 1.4em;
}
#shuffle,
#repeat {
  color: #949494;
  font-size: 1em;
}
.hide {
  display: none;
}
#progress-bar {
  position: relative;
  width: 100%;
  height: 0.3em;
  background-color: #eeeeee;
  margin: 1em 0;
  border-radius: 0.18em;
  cursor: pointer;
}
#current-progress {
  position: absolute;
  left: 0;
  top: 0;
  display: inline-block;
  height: 100%;
  width: 20%;
  background-color: #2887e3;
  border-radius: 0.18em;
}
.time-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: "Roboto Mono", monospace;
}
#playlist-container {
  background-color: #ffffff;
  position: absolute;
  width: 100%;
  height: 100%;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
  border-radius: 0.6em;
  padding: 2em 1em;
  font-family: "Poppins", sans-serif;
}
#close-button {
  background-color: transparent;
  border: none;
  height: 2em;
  width: 2em;
  cursor: pointer;
  margin-left: 90%;
}
ul {
  list-style-type: none;
}
li {
  display: flex;
  align-items: center;
  margin: 1em 0;
  cursor: pointer;
}
.playlist-song-details {
  margin-left: 1em;
}
.playlist-song-details > span {
  display: block;
}
#playlist-song-artist-album {
  color: #949494;
  font-size: 0.8em;
}
button.active i {
  color: #2887e3;
}
@media screen and (max-width: 450px) {
  .music-player {
    font-size: 14px;
  }
}

.playlist-image-container {
  width: 3em;
}

Javascript:

Lastly, we implement the functionality using javascript. Once again, copy the code below and paste it into your script file. We create the music player in 15 easy steps. These steps are:

  1. Create Initial References
  2. Create An Array For Song List
  3. Detect If It Is A Touch Device
  4. Format Time
  5. A Function To Set Song
  6. Function To Play Song
  7. Implement Function To Toggle Repeat Mode
  8. Function To Play Next Song
  9. Function To Pause Song
  10. Create Function To Play Previous Song
  11. Function To Toggle Shuffle Mode
  12. Adding Event Listener to Progress Bar
  13. Updating Progress Bar and Time
  14. Function To Create Playlist
  15. Function To Show & Hide Playlist
const prevButton = document.getElementById("prev");
const nextButton = document.getElementById("next");
const repeatButton = document.getElementById("repeat");
const shuffleButton = document.getElementById("shuffle");
const audio = document.getElementById("audio");
const songImage = document.getElementById("song-image");
const songName = document.getElementById("song-name");
const songArtist = document.getElementById("song-artist");
const pauseButton = document.getElementById("pause");
const playButton = document.getElementById("play");
const playlistButton = document.getElementById("playlist");
const maxDuration = document.getElementById("max-duration");
const currentTimeRef = document.getElementById("current-time");
const progressBar = document.getElementById("progress-bar");
const playlistContainer = document.getElementById("playlist-container");
const closeButton = document.getElementById("close-button");
const playlistSongs = document.getElementById("playlist-songs");
const currentProgress = document.getElementById("current-progress");

//index for songs
let index;

//initially loop=true
let loop = true;

const songsList = [
  {
    name: "Make Me Move",
    link: "make-me-move.mp3",
    artist: "Culture Code",
    image: "make-me-move.jpg",
  },
  {
    name: "Where We Started",
    link: "where-we-started.mp3",
    artist: "Lost Sky",
    image: "where-we-started.jpg",
  },
  {
    name: "On & On",
    link: "on-on.mp3",
    artist: "Cartoon",
    image: "on-on.jpg",
  },
  {
    name: "Throne",
    link: "throne.mp3",
    artist: "Rival",
    image: "throne.jpg",
  },
  {
    name: "Need You Now",
    link: "need-you-now.mp3",
    artist: "Venemy",
    image: "need-you-now.jpg",
  },
];

//events object
let events = {
  mouse: {
    click: "click",
  },
  touch: {
    click: "touchstart",
  },
};

let deviceType = "";

//Detect touch device

const isTouchDevice = () => {
  try {
    //We try to create TouchEvent(it would fail for desktops and throw error)
    document.createEvent("TouchEvent");
    deviceType = "touch";
    return true;
  } catch (e) {
    deviceType = "mouse";
    return false;
  }
};

//Format time (convert ms to seconds, minutes and add 0 id less than 10)
const timeFormatter = (timeInput) => {
  let minute = Math.floor(timeInput / 60);
  minute = minute < 10 ? "0" + minute : minute;
  let second = Math.floor(timeInput % 60);
  second = second < 10 ? "0" + second : second;
  return `${minute}:${second}`;
};

//set song
const setSong = (arrayIndex) => {
  //this extracts all the variables from the object
  let { name, link, artist, image } = songsList[arrayIndex];
  audio.src = link;
  songName.innerHTML = name;
  songArtist.innerHTML = artist;
  songImage.src = image;
  //display duration when metadata loads
  audio.onloadedmetadata = () => {
    maxDuration.innerText = timeFormatter(audio.duration);
  };
};

//play song
const playAudio = () => {
  audio.play();
  pauseButton.classList.remove("hide");
  playButton.classList.add("hide");
};

//repeat button
repeatButton.addEventListener("click", () => {
  if (repeatButton.classList.contains("active")) {
    repeatButton.classList.remove("active");
    audio.loop = false;
    console.log("repeat off");
  } else {
    repeatButton.classList.add("active");
    audio.loop = true;
    console.log("repeat on");
  }
});

//Next song
const nextSong = () => {
  //if loop is true then continue in normal order
  if (loop) {
    if (index == songsList.length - 1) {
      //If last song is being played
      index = 0;
    } else {
      index += 1;
    }
    setSong(index);

    playAudio();
  } else {
    //else find a random index and play that song
    let randIndex = Math.floor(Math.random() * songsList.length);
    console.log(randIndex);
    setSong(randIndex);
    playAudio();
  }
};

//pause song
const pauseAudio = () => {
  audio.pause();
  pauseButton.classList.add("hide");
  playButton.classList.remove("hide");
};

//previous song ( you can't go back to a randomly played song)
const previousSong = () => {
  if (index > 0) {
    pauseAudio();
    index -= 1;
  } else {
    //if first song is being played
    index = songsList.length - 1;
  }
  setSong(index);
  playAudio();
};

//next song when current song ends
audio.onended = () => {
  nextSong();
};

//Shuffle songs
shuffleButton.addEventListener("click", () => {
  if (shuffleButton.classList.contains("active")) {
    shuffleButton.classList.remove("active");
    loop = true;
    console.log("shuffle off");
  } else {
    shuffleButton.classList.add("active");
    loop = false;
    console.log("shuffle on");
  }
});

//play button
playButton.addEventListener("click", playAudio);

//next button
nextButton.addEventListener("click", nextSong);

//pause button
pauseButton.addEventListener("click", pauseAudio);

//prev button
prevButton.addEventListener("click", previousSong);

//if user clicks on progress bar
isTouchDevice();
progressBar.addEventListener(events[deviceType].click, (event) => {
  //start of progressBar
  let coordStart = progressBar.getBoundingClientRect().left;
  //mouse click position
  let coordEnd = !isTouchDevice() ? event.clientX : event.touches[0].clientX;
  let progress = (coordEnd - coordStart) / progressBar.offsetWidth;

  //set width to progress
  currentProgress.style.width = progress * 100 + "%";

  //set time
  audio.currentTime = progress * audio.duration;

  //play
  audio.play();
  pauseButton.classList.remove("hide");
  playButton.classList.add("hide");
});

//update progress every second
setInterval(() => {
  currentTimeRef.innerHTML = timeFormatter(audio.currentTime);
  currentProgress.style.width =
    (audio.currentTime / audio.duration.toFixed(3)) * 100 + "%";
});

//update time
audio.addEventListener("timeupdate", () => {
  currentTimeRef.innerText = timeFormatter(audio.currentTime);
});

//Creates playlist
const initializePlaylist = () => {
  for (let i in songsList) {
    playlistSongs.innerHTML += `<li class='playlistSong' onclick='setSong(${i})'>
            <div class="playlist-image-container">
                <img src="${songsList[i].image}"/>
            </div>
            <div class="playlist-song-details">
                <span id="playlist-song-name">
                    ${songsList[i].name}
                </span>
                <span id="playlist-song-artist-album">
                    ${songsList[i].artist}
                </span>
            </div>
        </li>`;
  }
};

//display playlist
playlistButton.addEventListener("click", () => {
  playlistContainer.classList.remove("hide");
});

//hide playlist
closeButton.addEventListener("click", () => {
  playlistContainer.classList.add("hide");
});

window.onload = () => {
  //initially first song
  index = 0;
  setSong(index);
  //create playlist
  initializePlaylist();
};

Related Videos

Create Custom Music Player in HTML CSS & JavaScript

Build a Music Player | Vanilla JavaScript

Build a Music Player with HTML CSS & JavaScript

Create A Music Website Using HTML CSS JAVASCRIPT | Add Music In HTML Website

 

#html #css #javascript

Create a Custom Music Player with HTML, CSS & JavaScript

MetricBase: Play/experimentation/single-binary Version Of Graphite

MetricBase

For play/experimentation/single-server version of Graphite.

Structure

Front-ends are pieces of code that talk to the world around it. They, in turn, talk to a backend.

Back-ends are chained, and commands modified/passed from one to the next until the request is processed in it's entirety.

Building

go get github.com/msiebuhr/MetricBase
go build ./bin/MetricBase/

Start the server

./MetricBase

It listens for the Graphite text protocol on TCP port 2003 and has a webserver running on http://localhost:8080/ that serves a simple front-end from /http-pub/.


OLD TOY PROJECT - NOT MAINTAINED

If you want to play around, feel free to fork the project and hack away. If you're thinking of serious use, I'll be happy to hand over the project.


Download Details:

Author: Msiebuhr
Source Code: https://github.com/msiebuhr/MetricBase 

#go #golang #play 

MetricBase: Play/experimentation/single-binary Version Of Graphite

Jupyter Notebook Kernel for Running ansible Tasks and Playbooks

Ansible Jupyter Kernel

Example Jupyter Usage

The Ansible Jupyter Kernel adds a kernel backend for Jupyter to interface directly with Ansible and construct plays and tasks and execute them on the fly.

Demo

Demo

Installation:

ansible-kernel is available to be installed from pypi but you can also install it locally. The setup package itself will register the kernel with Jupyter automatically.

From pypi

pip install ansible-kernel
python -m ansible_kernel.install

From a local checkout

pip install -e .
python -m ansible_kernel.install

For Anaconda/Miniconda

pip install ansible-kernel
python -m ansible_kernel.install --sys-prefix

Usage

Local install

    jupyter notebook
    # In the notebook interface, select Ansible from the 'New' menu

Container

docker run -p 8888:8888 benthomasson/ansible-jupyter-kernel

Then copy the URL from the output into your browser:
http://localhost:8888/?token=ABCD1234

Using the Cells

Normally Ansible brings together various components in different files and locations to launch a playbook and performs automation tasks. For this jupyter interface you need to provide this information in cells by denoting what the cell contains and then finally writing your tasks that will make use of them. There are Examples available to help you, in this section we'll go over the currently supported cell types.

In order to denote what the cell contains you should prefix it with a pound/hash symbol (#) and the type as listed here as the first line as shown in the examples below.

#inventory

The inventory that your tasks will use

#inventory
[all]
ahost ansible_connection=local
anotherhost examplevar=val

#play

This represents the opening block of a typical Ansible play

#play
name: Hello World
hosts: all
gather_facts: false

#task

This is the default cell type if no type is given for the first line

#task
debug:
#task
shell: cat /tmp/afile
register: output

#host_vars

This takes an argument that represents the hostname. Variables defined in this file will be available in the tasks for that host.

#host_vars Host1
hostname: host1

#group_vars

This takes an argument that represents the group name. Variables defined in this file will be available in the tasks for hosts in that group.

#group_vars BranchOfficeX
gateway: 192.168.1.254

#vars

This takes an argument that represents the filename for use in later cells

#vars example_vars
message: hello vars
#play
name: hello world
hosts: localhost
gather_facts: false
vars_files:
    - example_vars

#template

This takes an argument in order to create a templated file that can be used in later cells

#template hello.j2
{{ message }}
#task
template:
    src: hello.j2
    dest: /tmp/hello

#ansible.cfg

Provides overrides typically found in ansible.cfg

#ansible.cfg
[defaults]
host_key_checking=False

Examples

You can find various example notebooks in the repository

Using the development environment

It's possible to use whatever python development process you feel comfortable with. The repository itself includes mechanisms for using pipenv

pipenv install
...
pipenv shell

Author: ansible
Source Code:  https://github.com/ansible/ansible-jupyter-kernel
License: Apache-2.0 License

#jupyter #python 

Jupyter Notebook Kernel for Running ansible Tasks and Playbooks
Bella  Bauch

Bella Bauch

1638630481

Animated Search Bar, Bloc REST API & Co. - Part 02

A customizable, animated search bar, a framework to build your Flutter REST Api, a way to remove the hashtag from the adress bar of your Flutter Web App and many more Flutter and Dart packages were released in calendar week 2.

🕒 TIMESTAMPS:
00:00 - Start
00:27 - Welcome
00:39 - animated_image_list
01:06 - scale_size
01:34 - floating_bubbles
01:54 - sn_progress_dialog
02:14 - beamer
02:42 - fast_immutable_collections
03:20 - async_button_builder
03:38 - url_strategy
04:08 - bloc_rest_api
04:28 - anim_search_bar
04:43 - Closing words

#flutter #play #card 

Animated Search Bar, Bloc REST API & Co. - Part 02
Bella  Bauch

Bella Bauch

1638623160

Render Playing Cards, Animated Drawer & Co. - Part 01

Render playing cards in Flutter, animate your drawer-widget and many more possibilities open up with the Flutter & Dart package releases of week 01 of 2021.

🕒 TIMESTAMPS:

00:00 - Start
00:36 - Welcome
00:48 - raw_sound
01:06 - xuxu_ui
01:42 - popover
02:00 - material_snackbar
02:15 - stringr
02:32 - sort
02:54 - strengthpassword
03:36 - fancy_cursor
04:00 - animated_drawer
04:34 - playing_cards
05:07 - Connect Four Series
05:23 - Closing words

#flutter  #play  #card 

Render Playing Cards, Animated Drawer & Co. - Part 01
Ragib aburuken

Ragib aburuken

1631622772

Introducing New Multiplayer Tournament Feature: Chapayev 2

Chapayev 2: Best Checkers 3D board Game is a multiplayer online & offline board game that boosts the inner adrenaline rush.

In this thrilling, fast-paced, and competitive strategy game, you will fight for survival against your friend from all over the world to win tournaments and become a legend among your peers. You will have to use your wit, tactics, and cunning to formulate just the right strategy to outsmart your opponent in every battle.

It tests your intelligence, your strategy, and your knowledge. It will always be online multiplayer with great graphics and realistic physics – the game is designed to make you feel like you are fighting for your army.

The game is packed with new features never seen before in any other game of this genre. A brand new type of graphics engine renders even more stunning effects than any other checkers board game. Now the gameplay itself is even more exciting than ever before, with an increased number of players at the same time.

The game has recently launched the latest feature of Multiplayer Tourney. To know about the latest feature continue reading the article.

Win Multiplayer tourney and climb to the top of worldwide ranking tables or play for fun and win points!

Now let’s see how can you leverage the MultiPlayer Tourney update stepwise:

Step 1:

Step-1 - Chapayev 2

First, one player has to create a tournament using coins such as 500 coins, 1000 coins, etc.

Step 2:

Invite as many players as you want using your invite feature within the game.

For More Step CLICK HERE

 

#3dboardgame  #boardgame  #best3dboardgame  #mobileboardgame  #checkers  #checkersboardgame  #draughts  #draughtsgame  #checkers3dboardgame  #onlineboardgame  #mobilegame  #mobilegaming  #gaming  #gamer  #game  #bestmobilegame  #strategygame  #play  #players  #gamelovers  #mobilegamelovers  #proplayers  #challenge  #chapayev2  #multiplayergame 

Introducing New Multiplayer Tournament Feature: Chapayev 2
anita maity

anita maity

1625380926

Play store Blogger Template: Apps Download Blogger Theme

Do you want to create your own professional Google play APP store website in blogger? The layout of the app store blogger template should be similar to Google play store or APKpure. The simple and clean layout grabbing user attention.

In this article, You will find the best premium APP store blogger template design in 2021. You don’t need to remove footer credit, You can easily customize the footer link.

Sora APPS - Watch Demo

This is image title

Sora APPS is another beautiful and Premium APP store blogger template. In this theme, You can get professional Features app and games widgets.

It is a well SEO optimized and responsive layout in any device like Mobile, desktop, and tablets. It is easy to add the navigation links and mega menu.

The main features of this template like Search engine friendly, Fully customizable, Sidebar response blogger events, Fast loading in Google speed insights. It uses Ajax auto slider where you can add your popular posts as the carousel.

You also watch video documentation for full information about Sora apps. It provides a sidebar categories section with web icons and links. This template also provides related post widgets in your blog article.

Sure APK - Watch Demo

This is image title
Sure APK is also the greatest blogger template to showcase your premium apps and games. It is your best choice to use this template. It provides a very clean and minimal design and layouts.

The main features of this template such as full-width hero section, font awesome icons, Drop downlinks, Search icons, Easy to arrange sidebar elements, Google AdSense friendly, Fully SEO optimizable blogger template.

Other features such as Fast loading, easy to customize your app and games post layouts, Social sharing button, Google play, and download button. You can watch video documentation for you will be customized this template easily.

Read More

#blogger template #apps download blogger theme #play store blogger template

Play store Blogger Template: Apps Download Blogger Theme
Roberta  Ward

Roberta Ward

1595344320

Wondering how to upgrade your skills in the pandemic? Here's a simple way you can do it.

Corona Virus Pandemic has brought the world to a standstill.

Countries are on a major lockdown. Schools, colleges, theatres, gym, clubs, and all other public places are shut down, the country’s economy is suffering, human health is on stake, people are losing their jobs and nobody knows how worse it can get.

Since most of the places are on lockdown, and you are working from home or have enough time to nourish your skills, then you should use this time wisely! We always complain that we want some ‘time’ to learn and upgrade our knowledge but don’t get it due to our ‘busy schedules’. So, now is the time to make a ‘list of skills’ and learn and upgrade your skills at home!

And for the technology-loving people like us, Knoldus Techhub has already helped us a lot in doing it in a short span of time!

If you are still not aware of it, don’t worry as Georgia Byng has well said,

“No time is better than the present”

– Georgia Byng, a British children’s writer, illustrator, actress and film producer.

No matter if you are a developer (be it front-end or back-end) or a data scientisttester, or a DevOps person, or, a learner who has a keen interest in technology, Knoldus Techhub has brought it all for you under one common roof.

From technologies like Scala, spark, elastic-search to angular, go, machine learning, it has a total of 20 technologies with some recently added ones i.e. DAML, test automation, snowflake, and ionic.

How to upgrade your skills?

Every technology in Tech-hub has n number of templates. Once you click on any specific technology you’ll be able to see all the templates of that technology. Since these templates are downloadable, you need to provide your email to get the template downloadable link in your mail.

These templates helps you learn the practical implementation of a topic with so much of ease. Using these templates you can learn and kick-start your development in no time.

Apart from your learning, there are some out of the box templates, that can help provide the solution to your business problem that has all the basic dependencies/ implementations already plugged in. Tech hub names these templates as xlr8rs (pronounced as accelerators).

xlr8rs make your development real fast by just adding your core business logic to the template.

If you are looking for a template that’s not available, you can also request a template may be for learning or requesting for a solution to your business problem and tech-hub will connect with you to provide you the solution. Isn’t this helpful 🙂

Confused with which technology to start with?

To keep you updated, the Knoldus tech hub provides you with the information on the most trending technology and the most downloaded templates at present. This you’ll be informed and learn the one that’s most trending.

Since we believe:

“There’s always a scope of improvement“

If you still feel like it isn’t helping you in learning and development, you can provide your feedback in the feedback section in the bottom right corner of the website.

#ai #akka #akka-http #akka-streams #amazon ec2 #angular 6 #angular 9 #angular material #apache flink #apache kafka #apache spark #api testing #artificial intelligence #aws #aws services #big data and fast data #blockchain #css #daml #devops #elasticsearch #flink #functional programming #future #grpc #html #hybrid application development #ionic framework #java #java11 #kubernetes #lagom #microservices #ml # ai and data engineering #mlflow #mlops #mobile development #mongodb #non-blocking #nosql #play #play 2.4.x #play framework #python #react #reactive application #reactive architecture #reactive programming #rust #scala #scalatest #slick #software #spark #spring boot #sql #streaming #tech blogs #testing #user interface (ui) #web #web application #web designing #angular #coronavirus #daml #development #devops #elasticsearch #golang #ionic #java #kafka #knoldus #lagom #learn #machine learning #ml #pandemic #play framework #scala #skills #snowflake #spark streaming #techhub #technology #test automation #time management #upgrade

Wondering how to upgrade your skills in the pandemic? Here's a simple way you can do it.
Markus  Bartell

Markus Bartell

1592555911

Serialization in Lagom

Serialization in Lagom
Lagom uses Akka serialization mechanisms to bind serializers for each of the message sent over the wire. Preferably we use JSON. We can easily add Play-JSON serialization that is much more familiar to developers.

Why Serialization?

  • Persisting events and exchanging messages between the nodes of the cluster requires serialization.
  • Request and response messages uses serialization.
  • Without serialization it is not possible to deserialize old objects.

#lagom #microservices #play #scala #serialization

Serialization in Lagom