diff --git a/assets/js/barcode-scanner.js b/assets/js/barcode-scanner.js index d5aefe3e..07b1f433 100644 --- a/assets/js/barcode-scanner.js +++ b/assets/js/barcode-scanner.js @@ -1,28 +1,26 @@ import { BarcodeDetector } from "barcode-detector/ponyfill"; -const barcodeTest = async function () { - // check supported formats +const barcodeReaderSetup = async function () { const supportedFormats = await BarcodeDetector.getSupportedFormats(); - console.log(supportedFormats); - const barcodeDetector = new BarcodeDetector({ + return new BarcodeDetector({ // make sure the formats are supported - formats: ["qr_code"], + formats: supportedFormats, }); - - const imageFile = await fetch( - "https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=Hello%20world!", - ).then((resp) => resp.blob()); - - barcodeDetector.detect(imageFile).then(console.log); } export default { - mounted() { + async mounted() { + const detectedBarcodes = new Set([]); + const barcodeDetector = await barcodeReaderSetup(); const video = this.el; const constraints = { audio: false, - video: { width: 800, height: 600 }, + video: { + width: 800, height: 600, facingMode: { + ideal: "environment" + } + }, }; navigator.mediaDevices @@ -30,10 +28,20 @@ export default { .then((mediaStream) => { console.debug("Camera access allowed") this.pushEventTo(video, "camera:allowed", {}); - console.log(mediaStream); video.srcObject = mediaStream; video.onloadedmetadata = () => { video.play(); + this.scanInterval = window.setInterval(async () => { + const barcodes = await barcodeDetector.detect(video); + if (barcodes.length <= 0) return; + + barcodes.forEach(barcode => { + if (!detectedBarcodes.has(barcode.rawValue)) { + this.pushEventTo(video, "barcode:scanned", { number: barcode.rawValue }); + detectedBarcodes.add(barcode.rawValue); + }; + }); + }, 500) }; }) .catch((err) => { @@ -43,5 +51,6 @@ export default { }, destroyed() { this.el.srcObject.getTracks().forEach(track => track.stop()); + window.clearInterval(this.scanInterval); } } diff --git a/lib/music_brainz/api_impl.ex b/lib/music_brainz/api_impl.ex index 13273df6..3e8f5756 100644 --- a/lib/music_brainz/api_impl.ex +++ b/lib/music_brainz/api_impl.ex @@ -305,6 +305,15 @@ defmodule MusicBrainz.APIImpl do json_get(url, config) end + def search_release_by_barcode(barcode, config) do + url = + @base_url <> "/release?query=barcode:#{barcode}&fmt=json" + + with {:ok, result} <- json_get(url, config) do + {:ok, result["releases"]} + end + end + @doc """ Uses the [search](https://musicbrainz.org/doc/MusicBrainz_API/Search#Release_Group) endpoint with a search query string. diff --git a/lib/music_library/records.ex b/lib/music_library/records.ex index 0f1fc022..dc50b734 100644 --- a/lib/music_library/records.ex +++ b/lib/music_library/records.ex @@ -139,6 +139,16 @@ defmodule MusicLibrary.Records do end end + def search_release_by_barcode(barcode) do + case music_brainz_config().api.search_release_by_barcode(barcode, music_brainz_config()) do + {:ok, releases} -> + {:ok, releases} + + error -> + error + end + end + def import_from_musicbrainz_release_group(musicbrainz_id, opts \\ []) do with format = Keyword.get(opts, :format, "cd"), purchased_at = Keyword.get(opts, :purchased_at), diff --git a/lib/music_library_web/live/record_live/barcode_scanner_component.ex b/lib/music_library_web/live/record_live/barcode_scanner_component.ex index 29b7f377..a58cce9d 100644 --- a/lib/music_library_web/live/record_live/barcode_scanner_component.ex +++ b/lib/music_library_web/live/record_live/barcode_scanner_component.ex @@ -1,14 +1,32 @@ defmodule MusicLibraryWeb.RecordLive.BarcodeScannerComponent do use MusicLibraryWeb, :live_component + alias MusicLibrary.Records + require Logger + @impl true + def mount(socket) do + {:ok, + socket + |> assign(:camera, :pending) + |> assign(:barcodes, MapSet.new()) + |> assign(:releases, [])} + end + @impl true def render(assigns) do ~H"""

Barcode Scan

- + +
""" end @@ -23,4 +41,18 @@ defmodule MusicLibraryWeb.RecordLive.BarcodeScannerComponent do Logger.debug(fn -> "Camera access denied" end) {:noreply, assign(socket, camera: :denied)} end + + def handle_event("barcode:scanned", %{"number" => number}, socket) do + Logger.debug(fn -> "Scanned barcode #{number}" end) + + {:ok, releases} = + Records.search_release_by_barcode(number) + + socket = + socket + |> assign(barcodes: MapSet.put(socket.assigns.barcodes, number)) + |> assign(:releases, releases ++ socket.assigns.releases) + + {:noreply, socket} + end end