diff --git a/.gitignore b/.gitignore index 178638e..724aa35 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ node_modules/ *.jpg *.webp config.json +devices.csv devices.json package-lock.json \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e7fc96b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 The Mue Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index e694b89..812f028 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,34 @@ # uploader Internal uploading utility for Mue +## About +The process of uploading images to Mue was long and tedious - you had to generate a file name, add it to the database with the information, compress the image and then upload it and hope it works. This utility was made to make creating the new photo database in 5.2 a much easier process. The utility allows you to simply select a file, choose the category + photographer and click upload. + +## Features +* Supports converting jpg, png, cr3, cr2, dng, raf, fff, rwl, nef, rw2, x3f and arw files to webp +* Get formatted Mue location (e.g Manchester, United Kingdom) from EXIF data +* Get camera or phone model name (e.g Canon 1300D, Samsung Galaxy S8) +* Automatic listing of photographers and categories with an option to add new ones +* Undo button in case you made a mistake + ## Installation ### Requirements -* Cloudinary -* Supabase -* OpenCage (optional, used for getting location from exif coordinates) -### Instructions -1. ``git clone https://github.com/mue/uploader`` -2. ``cd uploader`` and ``npm i`` (or ``yarn``) -3. Move ``config-example.json`` to ``config.json`` and fill out your Cloudinary keys, Supabase API information and OpenCage API key. -4. ``npm start`` or ``yarn`` -5. Start developing! +* [Git](https://git-scm.com/) +* [Node.js](https://nodejs.org) +* [A free Cloudinary account](https://cloudinary.com/) +* [Mue API Instance](https://github.com/mue/api) +* [A free OpenCage API key](https://opencagedata.com/) (optional, used for getting location from exif coordinates) +### Starting +1. Clone the repository using ``git clone https://github.com/mue/uploader.git`` +2. Run ``npm i`` (or ``yarn``) to install all needed dependencies +3. Move ``config-example.json`` to ``config.json`` and add your keys etc +4. Run ``node getdevicelist.js`` to get the phone device list +5. ``npm start`` or ``yarn`` +6. Code your heart out! +### Building +1. ``npm run build`` + +Please note that currently it only returns a Windows build, and the uploader utility has not been tested on any other operating system. Due to the fact this program is useless without the correct setup, no prebuilt binaries are provided. + +## License +[MIT](LICENSE) \ No newline at end of file diff --git a/config-example.json b/config-example.json index 0fa7b2b..62567d6 100644 --- a/config-example.json +++ b/config-example.json @@ -9,5 +9,6 @@ "key": "" }, "opencage": "" - } + }, + "api_url": "" } \ No newline at end of file diff --git a/getdevicelist.js b/getdevicelist.js new file mode 100644 index 0000000..57d2c37 --- /dev/null +++ b/getdevicelist.js @@ -0,0 +1,17 @@ +const csv = require('convert-csv-to-json'); +const fetch = require('node-fetch'); +const fs = require('fs'); + +const downloadFile = (async (url, path) => { + const res = await fetch(url); + const stream = fs.createWriteStream(path); + await new Promise((resolve, reject) => { + res.body.pipe(stream); + res.body.on('error', reject); + stream.on('finish', resolve); + }); +}); + +downloadFile('https://storage.googleapis.com/play_public/supported_devices.csv', './devices.csv').then(() => { + csv.fieldDelimiter(',').ucs2Encoding().generateJsonFileFromCsv('devices.csv', 'devices.json'); +}); \ No newline at end of file diff --git a/package.json b/package.json index 22bf347..13ab9a5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,12 @@ { "name": "mue-uploader", - "author": "David Ralph", - "version": "1.0.0", + "private": true, + "repository": { + "url": "github:mue/uploader" + }, + "license": "MIT", + "author": "The Mue Authors (https://github.com/mue/uploader/graphs/contributors)", + "version": "1.1.0", "description": "Internal uploading utility for Mue", "scripts": { "start": "electron .", @@ -15,7 +20,9 @@ "sharp": "^0.28.3" }, "devDependencies": { + "convert-csv-to-json": "^1.3.1", "electron": "13.1.6", - "electron-builder": "^22.11.7" + "electron-builder": "^22.11.7", + "node-fetch": "^2.6.1" } } diff --git a/public/index.css b/public/index.css index 320d2d2..3b3cbdb 100644 --- a/public/index.css +++ b/public/index.css @@ -76,14 +76,14 @@ body { font-size: 14px; } -#title-bar-btns { +#title-bar-buttons { -webkit-app-region: no-drag; position: fixed; top: 1px; right: 0px; } -#title-bar-btns button { +#title-bar-buttons button { height: 32px; width: 32px; background-color: transparent; @@ -93,6 +93,6 @@ body { cursor: pointer; } -#title-bar-btns button:hover { +#title-bar-buttons button:hover { background-color: var(--tab-active); } \ No newline at end of file diff --git a/public/index.html b/public/index.html index b08fc23..9d501b9 100644 --- a/public/index.html +++ b/public/index.html @@ -6,10 +6,10 @@
Mue Uploader
-
- - - +
+ + +

Uploader

diff --git a/public/index.js b/public/index.js index 95ec1b0..cb2d065 100644 --- a/public/index.js +++ b/public/index.js @@ -25,10 +25,10 @@ ipcRenderer.on('addedFile', async (_event, arg, arg2) => { const phoneInfo = devices.find(device => device.model === arg.Model); const model = document.getElementById('model'); if (phoneInfo) { - if (phoneInfo.marketing_name.split(' ')[0] === phoneInfo.retail_branding) { - model.value = phoneInfo.marketing_name + if (phoneInfo['MarketingName'].split(' ')[0] === phoneInfo['RetailBranding']) { + model.value = phoneInfo['MarketingName']; } else { - model.value = phoneInfo.retail_branding + ' ' + phoneInfo.marketing_name; + model.value = phoneInfo['RetailBranding'] + ' ' + phoneInfo['MarketingName']; } } else { if (!arg.Make && !arg.Model) { @@ -45,8 +45,7 @@ ipcRenderer.on('addedFile', async (_event, arg, arg2) => { // find location from gps data if (config.tokens.opencage !== '' && arg.latitude && arg.longitude) { try { - const res = await fetch(`https://api.opencagedata.com/geocode/v1/json?q=${arg.latitude},${arg.longitude}&key=${config.tokens.opencage}`); - const location = await res.json(); + const location = await (await fetch(`https://api.opencagedata.com/geocode/v1/json?q=${arg.latitude},${arg.longitude}&key=${config.tokens.opencage}`)).json(); document.getElementById('location').value = location.results[0].components.town ? location.results[0].components.town + ', ' + location.results[0].components.country : location.results[0].components.country; } catch (e) { document.getElementById('location').value = ''; @@ -58,8 +57,7 @@ ipcRenderer.on('addedFile', async (_event, arg, arg2) => { // list of photographers const getPhotographers = async () => { - const res = await fetch('https://api.muetab.com/images/photographers'); - const photographers = await res.json(); + const photographers = await (await fetch(config.api_url + '/images/photographers')).json(); const dropdown = document.getElementById('photographer'); // in the future, we probably want to make the api sort alphabetically instead of doing it here photographers.sort().forEach((element) => { @@ -84,8 +82,7 @@ document.getElementById('photographer').onchange = (e) => { /// copy and pasted from above const getCategories = async () => { - const res = await fetch('https://api.muetab.com/images/categories'); - const categories = await res.json(); + const categories = await (await fetch(config.api_url + '/images/categories')).json(); const dropdown = document.getElementById('category'); categories.forEach((element) => { const option = document.createElement('option'); diff --git a/public/titlebar.js b/public/titlebar.js index 807a868..c2b72cf 100644 --- a/public/titlebar.js +++ b/public/titlebar.js @@ -1,13 +1,13 @@ const init = () => { - document.getElementById('min-btn').addEventListener('click', () => { + document.getElementById('min-button').addEventListener('click', () => { ipcRenderer.send('titlebar', 'minimize'); }); - document.getElementById('max-btn').addEventListener('click', () => { + document.getElementById('max-button').addEventListener('click', () => { ipcRenderer.send('titlebar', 'maximise'); }); - document.getElementById('close-btn').addEventListener('click', () => { + document.getElementById('close-button').addEventListener('click', () => { ipcRenderer.send('titlebar', 'close'); }); };