{"id":15659662,"url":"https://github.com/kopiro/tommy","last_synced_at":"2025-08-21T23:11:09.800Z","repository":{"id":46946099,"uuid":"151716761","full_name":"kopiro/tommy","owner":"kopiro","description":" Web assets optimverter","archived":false,"fork":false,"pushed_at":"2022-12-09T05:19:58.000Z","size":3787,"stargazers_count":21,"open_issues_count":5,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-05T04:03:44.870Z","etag":null,"topics":["assets","converter","docker","ffmpeg","gifsicle","imagemagick","jpegoptim","npm","optimizer","pngquant","web"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kopiro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-05T12:22:12.000Z","updated_at":"2023-03-23T09:58:58.000Z","dependencies_parsed_at":"2023-01-25T11:00:40.283Z","dependency_job_id":null,"html_url":"https://github.com/kopiro/tommy","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kopiro%2Ftommy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kopiro%2Ftommy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kopiro%2Ftommy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kopiro%2Ftommy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kopiro","download_url":"https://codeload.github.com/kopiro/tommy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252436291,"owners_count":21747470,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assets","converter","docker","ffmpeg","gifsicle","imagemagick","jpegoptim","npm","optimizer","pngquant","web"],"created_at":"2024-10-03T13:18:08.874Z","updated_at":"2025-05-05T04:03:50.445Z","avatar_url":"https://github.com/kopiro.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tommy: web assets optimverter\n\nTommy will process, optimize and convert all your static assets ready to use for the web.\n\n[![npm version](http://img.shields.io/npm/v/kopiro-tommy.svg?style=flat)](https://npmjs.org/package/kopiro-tommy \"View this project on npm\")\n[![docker version](https://img.shields.io/docker/pulls/kopiro/tommy.svg)](https://hub.docker.com/r/kopiro/tommy)\n\n\u003cimg width=\"80%\" src=\"render.gif\" /\u003e\n\n## Arguments\n\n- `--src` specify the source directory (where your assets are located)\n- `--dst` specify the destination directory (where your assets will be generated)\n\n### Optional argumenmts\n\n- `--force` regenerate all assets ignoring cache\n- `--config` specify a JSON file containing an extension to the configuration\n- `--webserver` will spawn an HTTP webserver that access via `POST /` a request to run\n- `--port` is the webserver port (default: 80)\n- `--watch` will enable a persistent watch over the src directory to detect instant file changes\n\n**⚡️️️ Always set `--dst` option to an empty directory: this directory should only be used by Tommy because files in could be potentially deleted if Tommy is started with a weird configuration or a corrupted database ⚡️**\n\n## How to: run with Docker\n\nThe main advantage of using Tommy is that all dependencies used to process/convert entities are encapsulated into a docker image.\n\nFor this reason, you should use the `docker run` command to use Tommy in the original way it was created.\n\n```sh\ndocker run \\\n-v \"$(pwd)/test/src\":/src \\\n-v \"$(pwd)/test/dst\":/dst \\\n-v \"$(pwd)/config.json:/root/config.json\" \\\nkopiro/tommy:latest \\\n--src /src \\\n--dst /dst \\\n--config /root/config.json\n```\n\nExplanation of mounts:\n\n- `-v \"$(pwd)/test/src\":/src` mount the source directory (where your assets are located) into container `/src`\n- `-v \"$(pwd)/test/dst\":/dst` mount the destination directory (where your assets will be generated) into container `/dst`\n- `-v \"$(pwd)/config.json:/root/config.json\"` mount your (optional) configuration JSON file into container `/root/config.json`\n\n### How to: run in MacOS\n\nYou can also use the native NPM package on OSX.\n\n#### Installation\n\n```sh\nnpm -g i kopiro-tommy\n```\n\n#### Run\n\n```sh\ntommy --src ./test/src --dst ./test/dst\n```\n\n## Configuration\n\nBy providing a JSON file to `--config`, you configuration will be extended with the default one.\n\n```sh\ntommy --config config.json\n```\n\nExample:\n\n```json\n{\n  \"processor.resize\": {\n    \"enabled\": false\n  },\n  \"processor.resize\": {\n    \"enabled\": true,\n    \"suffix\": \"-resized-${i}.${ext}\",\n    \"dimensions\": [100, 300],\n    \"quality\": 60\n  },\n  \"ignore\": [\".dockerignore\"]\n}\n```\n\n### First-level keys\n\n| Key    | Type     | Description       | Default           |\n| ------ | -------- | ----------------- | ----------------- |\n| ignore | string[] | Pattern to ignore | _see config.json_ |\n\n## Available services\n\n### Images\n\n| Key                        | Applies to   | Description                                                                                    |\n| -------------------------- | ------------ | ---------------------------------------------------------------------------------------------- |\n| processor.resize           | \\*           | resize the image in differents formats                                                         |\n| processor.image            | \\*           | optimize the image                                                                             |\n| processor.lazyLoadBlurried | \\*           | generates a very small blurried image that can be used before loading final image in lazy load |\n| converter.webp             | \\*           | converts to WEBP format                                                                        |\n| tester.image               | \\*           | generates a sample HTML page to test all differents formats                                    |\n| processor.jpg              | \\*.jpg       | optimizes the JPG using `jpegoptim`                                                            |\n| processor.png              | \\*.png       | optimizes the PNG using `pngquant`                                                             |\n| processor.gif              | \\*.gif       | optimizes the GIF using `gifsicle`                                                             |\n| processor.svg              | \\*.svg       | optimizes the SVG using `svgo`                                                                 |\n| processor.favicon          | /favicon.png | generates all images/icons needed in various browsers for the favicon                          |\n\n### Videos\n\n| Key                   | Applies to | Description                                                                                        |\n| --------------------- | ---------- | -------------------------------------------------------------------------------------------------- |\n| processor.poster      | \\*         | generates a representative poster image from the video to use as picture before loading the video. |\n| processor.videoThumbs | \\*         | generates N different thumbs from the video                                                        |\n| converter.webm        | \\*         | converts to WEBM format                                                                            |\n| converter.h264_mp4    | \\*         | converts to H264 using MP4 container                                                               |\n| converter.av1_mp4     | \\*         | converts to AV1 using MP4 container. **currently disabled by default because it's very very slow** |\n| converter.hevc_mp4    | \\*         | converts to HEVC using MP4 container                                                               |\n| tester.video          | \\*         | generates a sample HTML page to test all differents formats                                        |\n\n### Fonts\n\n| Key             | Applies to | Description                                                 |\n| --------------- | ---------- | ----------------------------------------------------------- |\n| converter.ttf   | \\*         | converts to TTF format                                      |\n| converter.otf   | \\*         | converts to OTF format                                      |\n| converter.eot   | \\*         | converts to EOT format                                      |\n| converter.svg   | \\*         | converts to SVG format                                      |\n| converter.woff  | \\*         | converts to WOFF format                                     |\n| converter.woff2 | \\*         | converts to WOFF2 format                                    |\n| tester.font     | \\*         | generates a sample HTML page to test all differents formats |\n\n### Audios\n\n| Key           | Applies to | Description            |\n| ------------- | ---------- | ---------------------- |\n| converter.mp3 | \\*         | converts to MP3 format |\n\n### Disabling service\n\nBy settings `enabled: false` in a key, you'll disable that service.\n\n```json\n...\n\"processor.resize\": {\n   \"enabled\": false\n}\n...\n```\n\n## Specific configurations for services\n\n### processor.resize\n\n| Key        | Type     | Description                                       | Default                  |\n| ---------- | -------- | ------------------------------------------------- | ------------------------ |\n| dimensions | number[] | Dimensions of resized images in PX (longest side) | `[200,400,800,1200]`     |\n| quality    | number   | Quality of images                                 | `80`                     |\n| suffix     | string   | Suffix to Applies to new files                    | `\"-resized-${i}.${ext}\"` |\n\n### processor.image\n\n| Key     | Type   | Description      | Default |\n| ------- | ------ | ---------------- | ------- |\n| quality | number | Quality of image | `80`    |\n\n### processor.videoThumbs\n\n| Key     | Type   | Description                    | Default              |\n| ------- | ------ | ------------------------------ | -------------------- |\n| count   | number | How many thumbnails extract    | `5`                  |\n| size    | number | Length of longest side         | `400`                |\n| quality | number | Quality of image               | `80`                 |\n| suffix  | string | Suffix to Applies to new files | `\"-thumb-\\${i}.jpg\"` |\n\n### processor.lazyLoadBlurried\n\n| Key    | Type   | Description                    | Default           |\n| ------ | ------ | ------------------------------ | ----------------- |\n| size   | number | Length of longest side         | `10`              |\n| suffix | string | Suffix to Applies to new files | `\"-blurried.jpg\"` |\n\n### processor.poster\n\n| Key    | Type   | Description                    | Default         |\n| ------ | ------ | ------------------------------ | --------------- |\n| suffix | string | Suffix to Applies to new files | `\"-poster.jpg\"` |\n\n### processor.favicon\n\n| Key           | Type   | Description                                                                             | Default           |\n| ------------- | ------ | --------------------------------------------------------------------------------------- | ----------------- |\n| webmanifest   | object | JSON object to extend for the `site.webmanifest`. Set to `false` to disable generation. | _see config.json_ |\n| browserconfig | bool   | Set to `false` to disable generation of `browserconfig.xml`                             | `true`            |\n| test          | bool   | Set to `false` to disable HTML test page (`favicon.html`)                               | `true`            |\n| tileColor     | string | Color of the tile for Windows                                                           | `\"#336699\"`       |\n| themeColor    | string | Color of the theme for Chrome Mobile                                                    | `\"#336699\"`       |\n\n## convert.{webm,\\*\\_mp4}\n\n_These are the general settings used for video. You can override manually in every section_\n\n| Key         | Type   | Description                                                                                                   | Default        |\n| ----------- | ------ | ------------------------------------------------------------------------------------------------------------- | -------------- |\n| audioCodec  | string | The coded to use for audio                                                                                    | `null`         |\n| crf         | number | The range of the CRF scale is 0–51, where 0 is lossless, 23 is the default, and 51 is worst quality possible. | `23`           |\n| pixelFormat | string | It uses full resolution for brightness and a smaller resolution for color.                                    | `\"yuv420p\"`    |\n| mapMetadata | string | Choose to keep/remove metadata                                                                                | `\"-1\"`         |\n| movFlags    | string | Movie flags to pass to ffmpeg                                                                                 | `\"+faststart\"` |\n| preset      | string | Will provide a certain encoding speed to compression ratio.                                                   | `\"medium\"`     |\n\n### converter.webm\n\n| Key        | Type   | Description           | Default        |\n| ---------- | ------ | --------------------- | -------------- |\n| videoCodec | string | _see general section_ | `\"libvpx-vp9\"` |\n\n### converter.h264_mp4\n\n| Key        | Type   | Description           | Default     |\n| ---------- | ------ | --------------------- | ----------- |\n| videoCodec | string | _see general section_ | `\"libx264\"` |\n\n### converter.av1_mp4\n\n| Key        | Type   | Description                                                                                 | Default        |\n| ---------- | ------ | ------------------------------------------------------------------------------------------- | -------------- |\n| videoCodec | string | _see general section_                                                                       | `\"libaom-av1\"` |\n| audioCoded | string | _see general section_                                                                       | `\"libopus\"`    |\n| crf        | number | _see general section_ (note: this value is higher due te different scale of this algorithm) | `50`           |\n\n### converter.hvec_mp4\n\n| Key        | Type   | Description                | Default     |\n| ---------- | ------ | -------------------------- | ----------- |\n| videoCodec | string | The coded to use for video | `\"libx265\"` |\n\n## Howto: testing locally\n\nYou can use the command `npm run test-docker` to build the image and test against a test directory.\n\nIf you need samples, run `npm run download-samples`\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkopiro%2Ftommy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkopiro%2Ftommy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkopiro%2Ftommy/lists"}