├── .czrc ├── .editorconfig ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md └── workflows │ └── ci.yml ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg ├── pre-commit ├── pre-push └── prepare-commit-msg ├── .nvmrc ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── assets └── logo.png ├── commitlint.config.js ├── docs ├── _config.yml ├── core │ ├── README.md │ ├── classes │ │ ├── src.catalogdatabase.md │ │ ├── src.catalogmapper.md │ │ ├── src.database.md │ │ ├── src.languagemapper.md │ │ ├── src.mediacatalogmapper.md │ │ ├── src.publication.md │ │ └── src.publicationmapper.md │ ├── enums │ │ ├── src.publication_classes.md │ │ └── src.publication_types.md │ ├── interfaces │ │ ├── types_database.articlerow.md │ │ ├── types_database.imagerow.md │ │ ├── types_database.languagerow.md │ │ ├── types_database.mediadetailsrow.md │ │ ├── types_database.publicationrow.md │ │ ├── types_database.relatedpublicationrow.md │ │ ├── types_database.videorowbase.md │ │ ├── types_database.videorowdoc.md │ │ ├── types_database.videorowpub.md │ │ ├── types_dto.imagedto.md │ │ ├── types_dto.languagedto.md │ │ ├── types_dto.mediacatalogdatabasedto.md │ │ ├── types_dto.mediacatalogitemdto.md │ │ ├── types_dto.mediadetailsdto.md │ │ ├── types_dto.relatedpublicationdto.md │ │ ├── types_dto.videodto.md │ │ ├── types_hag.getmediapublinks.md │ │ ├── types_hag.mediapublink.md │ │ ├── types_media.catalogschemaversionrow.md │ │ ├── types_media.categoryrow.md │ │ ├── types_media.categoryrowobjcontainer.md │ │ ├── types_media.categoryrowobjondemand.md │ │ ├── types_media.imagesizes.md │ │ ├── types_media.languagerow.md │ │ ├── types_media.mediacatalogctor.md │ │ ├── types_media.mediaitemrow.md │ │ ├── types_media.signaturerow.md │ │ └── types_publication.publicationctor.md │ └── modules │ │ ├── src.md │ │ ├── types_database.md │ │ ├── types_dto.md │ │ ├── types_hag.md │ │ ├── types_media.md │ │ └── types_publication.md ├── express │ └── README.md ├── index.md └── media │ └── README.md ├── jest.config.base.ts ├── lerna.json ├── lint-staged.config.js ├── package.json ├── packages ├── core │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── src │ │ ├── catalog.ts │ │ ├── classes │ │ │ ├── Database.ts │ │ │ ├── Mapper.ts │ │ │ ├── Media.ts │ │ │ ├── Publication.ts │ │ │ └── index.ts │ │ ├── constants.ts │ │ ├── data │ │ │ └── languages.json │ │ ├── download.ts │ │ ├── index.ts │ │ ├── language.ts │ │ └── utils.ts │ ├── test │ │ ├── .eslintrc.js │ │ ├── classes │ │ │ └── Mapper.spec.ts │ │ └── tsconfig.json │ ├── tsconfig.json │ ├── typedoc.js │ └── types │ │ ├── database.d.ts │ │ ├── dto.d.ts │ │ ├── hag.d.ts │ │ ├── media.d.ts │ │ └── publication.d.ts ├── express │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── router │ │ │ ├── catalog.ts │ │ │ ├── download.ts │ │ │ ├── index.ts │ │ │ ├── media.ts │ │ │ └── publication.ts │ │ └── server.ts │ ├── test │ │ ├── .eslintrc.js │ │ ├── server.spec.ts │ │ └── tsconfig.json │ ├── tsconfig.json │ └── types │ │ └── api.d.ts └── media │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── app │ ├── main │ │ ├── .eslintrc.js │ │ ├── src │ │ │ ├── constants.ts │ │ │ ├── directories.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ ├── ipc.ts │ │ │ ├── logger.ts │ │ │ ├── menu.ts │ │ │ ├── updater.ts │ │ │ └── window.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── preload │ │ ├── src │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── renderer │ │ ├── .eslintrc.js │ │ ├── index.html │ │ ├── src │ │ │ ├── App.vue │ │ │ ├── assets │ │ │ │ ├── Quicksand.ttf │ │ │ │ ├── close.svg │ │ │ │ ├── download.svg │ │ │ │ ├── logo-banner.png │ │ │ │ ├── logo-line.png │ │ │ │ ├── logo.svg │ │ │ │ ├── media.svg │ │ │ │ ├── picker.svg │ │ │ │ ├── settings.svg │ │ │ │ └── song.svg │ │ │ ├── components │ │ │ │ ├── Controls.vue │ │ │ │ ├── Loader.vue │ │ │ │ ├── Navbar.vue │ │ │ │ ├── NavbarBtn.vue │ │ │ │ └── PreviewMedia.vue │ │ │ ├── composables │ │ │ │ └── store.ts │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ │ ├── ControlPanel │ │ │ │ │ ├── Index.vue │ │ │ │ │ ├── Media.vue │ │ │ │ │ ├── Picker.vue │ │ │ │ │ ├── Settings.vue │ │ │ │ │ └── Song.vue │ │ │ │ ├── Display.vue │ │ │ │ └── Intro.vue │ │ │ ├── router │ │ │ │ └── index.ts │ │ │ └── utils │ │ │ │ └── date.ts │ │ ├── tsconfig.json │ │ ├── types │ │ │ ├── select.d.ts │ │ │ └── shims-vue.d.ts │ │ └── vite.config.ts │ └── shared │ │ ├── src │ │ ├── extensions.ts │ │ └── store.ts │ │ ├── tsconfig.json │ │ └── types │ │ ├── electron-api.d.ts │ │ ├── ipc.d.ts │ │ ├── store.d.ts │ │ └── window.d.ts │ ├── buildResources │ ├── entitlements.mac.plist │ └── icon.png │ ├── electron-builder.package.config.js │ ├── electron-builder.release.config.js │ ├── jest.config.ts │ ├── package.json │ ├── scripts │ ├── build.js │ ├── notarize.js │ └── watch.js │ ├── test │ ├── .eslintrc.js │ ├── renderer │ │ └── utils │ │ │ └── date.spec.ts │ └── tsconfig.json │ └── tsconfig.json ├── tsconfig.base.json ├── vetur.config.js └── yarn.lock /.czrc: -------------------------------------------------------------------------------- 1 | { 2 | "path": "cz-conventional-changelog" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type { import('eslint').Linter.Config } 3 | */ 4 | module.exports = { 5 | root: true, 6 | env: { 7 | es2021: true, 8 | node: true, 9 | browser: false 10 | }, 11 | extends: [ 12 | 'standard', 13 | 'plugin:@typescript-eslint/recommended' 14 | ], 15 | parserOptions: { 16 | parser: '@typescript-eslint/parser', 17 | ecmaVersion: 12, 18 | sourceType: 'module' 19 | }, 20 | plugins: [ 21 | '@typescript-eslint' 22 | ], 23 | ignorePatterns: [ 24 | 'dist/*' 25 | ], 26 | rules: { 27 | // typescript handles this for us 28 | 'no-use-before-define': 'off' 29 | }, 30 | overrides: [ 31 | { 32 | files: ['*.js'], 33 | rules: { 34 | '@typescript-eslint/no-var-requires': 'off' 35 | } 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '[Bug] ' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Packages & versions** 11 | 12 | 13 | 14 | 15 | **Describe the bug** 16 | 17 | 18 | 19 | **Reproduction steps** 20 | 21 | 22 | 23 | **Expected behavior** 24 | 25 | 26 | 27 | **Additional context** 28 | 29 | 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '[Feature] ' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Packages** 11 | 12 | 13 | 14 | **Describe the solution you'd like** 15 | 16 | 17 | 18 | **Describe alternatives you've considered** 19 | 20 | 21 | 22 | **Additional context** 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # Testing this workflow is possible using https://github.com/nektos/act 2 | # Act only steps are specified by `if: ${{ env.ACT }}` 3 | 4 | name: CI 5 | 6 | on: push 7 | 8 | jobs: 9 | test: 10 | name: Test 11 | runs-on: macos-10.15 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 17 | - name: Read .nvmrc 18 | id: nvm 19 | run: echo ::set-output name=NVMRC::$(cat .nvmrc) 20 | - name: Setup Node 21 | uses: actions/setup-node@v2 22 | with: 23 | node-version: '${{ steps.nvm.outputs.NVMRC }}' 24 | - name: Install yarn 25 | if: ${{ env.ACT }} 26 | run: npm install -g yarn 27 | - name: Install dependencies 28 | run: yarn bootstrap 29 | - name: Unit Test 30 | run: yarn test:ci 31 | release: 32 | name: Release 33 | runs-on: macos-10.15 34 | needs: test 35 | if: github.ref == 'refs/heads/master' 36 | env: 37 | HUSKY: 0 38 | steps: 39 | - name: Checkout 40 | uses: actions/checkout@v2 41 | with: 42 | ref: 'master' 43 | fetch-depth: 0 44 | - name: Read .nvmrc 45 | id: nvm 46 | run: echo ::set-output name=NVMRC::$(cat .nvmrc) 47 | - name: Setup Node 48 | uses: actions/setup-node@v2 49 | with: 50 | node-version: '${{ steps.nvm.outputs.NVMRC }}' 51 | - name: Install yarn 52 | if: ${{ env.ACT }} 53 | run: npm install -g yarn 54 | - name: Install dependencies 55 | run: yarn bootstrap 56 | - name: Setup Git 57 | uses: oleksiyrudenko/gha-git-credentials@v2-latest 58 | with: 59 | token: ${{ secrets.GITHUB_TOKEN }} 60 | - name: Update Versions 61 | env: 62 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 63 | run: yarn lerna version --yes 64 | - name: Publish NPM Packages 65 | env: 66 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 67 | run: | 68 | echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc 69 | yarn lerna publish from-package --yes 70 | - name: Write Github Release 71 | env: 72 | GH_RELEASE_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 73 | run: yarn gh-release --yes 74 | # In the case no changes to version were made 75 | continue-on-error: true 76 | - name: Build MacOS Application 77 | env: 78 | CSC_LINK: ${{ secrets.CSC_LINK }} 79 | CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} 80 | APPLE_ID: ${{ secrets.APPLE_ID }} 81 | APPLE_ID_PASS: ${{ secrets.APPLE_ID_PASS }} 82 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 83 | run: | 84 | yarn media build 85 | yarn media release 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | npm-debug.log* 3 | yarn-debug.log* 4 | yarn-error.log* 5 | 6 | # Dependency directories 7 | node_modules/ 8 | 9 | # TypeScript cache 10 | *.tsbuildinfo 11 | 12 | # Optional npm cache directory 13 | .npm 14 | 15 | # Optional eslint cache 16 | .eslintcache 17 | 18 | # Optional REPL history 19 | .node_repl_history 20 | 21 | # Yarn Integrity file 22 | .yarn-integrity 23 | 24 | # dotenv environment variables file 25 | .env 26 | .env.test 27 | electron-builder.env 28 | 29 | # Output 30 | coverage 31 | dist 32 | downloads 33 | 34 | # System Files 35 | .DS_Store 36 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn commitlint --edit "$1" 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged 5 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn test:ci 5 | -------------------------------------------------------------------------------- /.husky/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | exec < /dev/tty && node_modules/.bin/cz --hook || true 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14.15.4 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "orta.vscode-jest", 8 | "editorconfig.editorconfig", 9 | "dbaeumer.vscode-eslint" 10 | ], 11 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 12 | "unwantedRecommendations": [ 13 | 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": true 4 | }, 5 | "jest.jestCommandLine": "yarn jest", 6 | "typescript.tsdk": "node_modules/typescript/lib" 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Library API Logo 3 |

4 | 5 |

6 | Library API 7 |

8 | 9 |

10 | 11 | Github Actions Status 12 | 13 | 14 | TypeScript 15 | 16 | 17 | Commitizen friendly 18 | 19 | 20 | lerna 21 | 22 | 23 | license 24 | 25 |

26 | 27 |

28 | An API for accessing information related to meetings and publications of Jehovah's Witnesses. 29 |

30 | 31 |
32 | 33 | ## 📦 Packages 34 | 35 | Library API offers the following packages: 36 | 37 | | Package | Description | Changelog | 38 | | ----------------------------------------------- | ---------------------------------------------------------------------------- | :-------------------------------------: | 39 | | [Library Media](./packages/media/README.md) | A **desktop app** that makes sharing meeting media easy | [View](./packages/media/CHANGELOG.md) | 40 | | [Library Express](./packages/express/README.md) | An **express server** for providing easy access to publication information | [View](./packages/express/CHANGELOG.md) | 41 | | [Library Core](./packages/core/README.md) | **Core tools** used in other packages that can be used to build your own app | [View](./packages/core/CHANGELOG.md) | 42 | 43 | ## 📖 Documentation 44 | 45 | Documentation for all packages can be viewed [here](https://benshelton.github.io/library-api/). 46 | 47 | ## 💡 Motivation 48 | 49 | There is no publicly available API for this information and the data structure is not created in a way to make things simple to parse or access. 50 | 51 | These packages aim to provide an API that provides the information without having to dig into the internals of existing apps. 52 | 53 | We also aim to provide sample applications that use this API. 54 | 55 | ## ❓ Support 56 | 57 | For instructions on how to use the individual packages view them using the links above. 58 | 59 | If you have any issues or feature requests please check if this had already been suggested on [our issues page](https://github.com/BenShelton/library-api/issues) and if not then select "New issue". 60 | 61 | ## 🛠 Development 62 | 63 | If you would like to contribute then thank you in advance! Library API uses the following tools for development you will need to install: 64 | 65 | - [VSCode](https://code.visualstudio.com/) as an IDE, you should be prompted to install recommended extensions when first opening the project 66 | - [Yarn (Classic)](https://classic.yarnpkg.com/en/) for package management 67 | 68 | You may also want to be familiar with the following (although some of these are automatic): 69 | 70 | - [TypeScript](https://www.typescriptlang.org/) is the main language 71 | - [Husky](https://typicode.github.io/husky/#/) is used to set up git hooks 72 | - [Commitizen](https://github.com/commitizen/cz-cli) and [commitlint](https://github.com/conventional-changelog/commitlint) enforce commit message styling 73 | 74 | Run the following commands to get started: 75 | 76 | ```bash 77 | # Bootstrap project (install dependencies & build TS definitions) 78 | yarn bootstrap 79 | 80 | # Run a command in a certain workspace 81 | yarn workspace [workspace] [command] 82 | # For example to run `yarn dev` in the `express` workspace 83 | yarn workspace @library-api/express dev 84 | # Shortcuts exist for the main packages, this is equivalent to the above 85 | yarn express dev 86 | ``` 87 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenShelton/library-api/bafb9731bc1166069f3bc6dff4796f31fd5907ed/assets/logo.png -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'] 3 | } 4 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate 2 | title: Library API Documentation 3 | description: Documentation for Library API Packages 4 | -------------------------------------------------------------------------------- /docs/core/README.md: -------------------------------------------------------------------------------- 1 | Library Core 2 | 3 | # Library Core 4 | 5 | ## Table of contents 6 | 7 | ### Modules 8 | 9 | - [src](modules/src.md) 10 | - [types/database](modules/types_database.md) 11 | - [types/dto](modules/types_dto.md) 12 | - [types/hag](modules/types_hag.md) 13 | - [types/media](modules/types_media.md) 14 | - [types/publication](modules/types_publication.md) 15 | -------------------------------------------------------------------------------- /docs/core/classes/src.catalogmapper.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [src](../modules/src.md) / CatalogMapper 2 | 3 | # Class: CatalogMapper 4 | 5 | [src](../modules/src.md).CatalogMapper 6 | 7 | Maps raw Catalog database rows to more accessible DTOs. 8 | 9 | ## Table of contents 10 | 11 | ### Constructors 12 | 13 | - [constructor](src.catalogmapper.md#constructor) 14 | 15 | ### Methods 16 | 17 | - [MapMediaDetails](src.catalogmapper.md#mapmediadetails) 18 | 19 | ## Constructors 20 | 21 | ### constructor 22 | 23 | • **new CatalogMapper**() 24 | 25 | ## Methods 26 | 27 | ### MapMediaDetails 28 | 29 | ▸ **MapMediaDetails**(`details`): [MediaDetailsDTO](../interfaces/types_dto.mediadetailsdto.md) 30 | 31 | Maps a raw Media Details database row to a Media Details DTO. 32 | 33 | #### Parameters 34 | 35 | | Name | Type | Description | 36 | | :------ | :------ | :------ | 37 | | `details` | [MediaDetailsRow](../interfaces/types_database.mediadetailsrow.md) | The database row. | 38 | 39 | #### Returns 40 | 41 | [MediaDetailsDTO](../interfaces/types_dto.mediadetailsdto.md) 42 | 43 | #### Defined in 44 | 45 | [src/classes/Mapper.ts:150](https://github.com/BenShelton/library-api/blob/master/packages/core/src/classes/Mapper.ts#L150) 46 | -------------------------------------------------------------------------------- /docs/core/classes/src.database.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [src](../modules/src.md) / Database 2 | 3 | # Class: Database 4 | 5 | [src](../modules/src.md).Database 6 | 7 | Wraps a `sqlite3` database and provides abstracted methods to access database information. 8 | 9 | ## Hierarchy 10 | 11 | - **Database** 12 | 13 | ↳ [CatalogDatabase](src.catalogdatabase.md) 14 | 15 | ## Table of contents 16 | 17 | ### Constructors 18 | 19 | - [constructor](src.database.md#constructor) 20 | 21 | ### Methods 22 | 23 | - [getRow](src.database.md#getrow) 24 | - [getRows](src.database.md#getrows) 25 | 26 | ## Constructors 27 | 28 | ### constructor 29 | 30 | • **new Database**(`path`) 31 | 32 | #### Parameters 33 | 34 | | Name | Type | Description | 35 | | :------ | :------ | :------ | 36 | | `path` | `string` | The path to the database. | 37 | 38 | #### Defined in 39 | 40 | [src/classes/Database.ts:21](https://github.com/BenShelton/library-api/blob/master/packages/core/src/classes/Database.ts#L21) 41 | 42 | ## Methods 43 | 44 | ### getRow 45 | 46 | ▸ **getRow**(`query`, `params?`): `Promise` 47 | 48 | Returns the first matched row of the provided query. 49 | The return type must be provided in TS as the row structure is unknown. 50 | 51 | **`example`** 52 | ```ts 53 | const db = new Database(path) 54 | const row = await db.getRow(query) 55 | ``` 56 | 57 | #### Type parameters 58 | 59 | | Name | 60 | | :------ | 61 | | `T` | 62 | 63 | #### Parameters 64 | 65 | | Name | Type | Description | 66 | | :------ | :------ | :------ | 67 | | `query` | `string` | The SQL query to run. | 68 | | `params?` | `QueryParams` | Query params to use. | 69 | 70 | #### Returns 71 | 72 | `Promise` 73 | 74 | A single row if it exists, or `undefined` if not found. 75 | 76 | #### Defined in 77 | 78 | [src/classes/Database.ts:49](https://github.com/BenShelton/library-api/blob/master/packages/core/src/classes/Database.ts#L49) 79 | 80 | ___ 81 | 82 | ### getRows 83 | 84 | ▸ **getRows**(`query`, `params?`): `Promise` 85 | 86 | Returns all matched rows of the provided query. 87 | The return type of a single row must be provided in TS as the row structure is unknown. 88 | 89 | **`example`** 90 | ```ts 91 | const db = new Database(path) 92 | const rows = await db.getRows(query) 93 | ``` 94 | 95 | #### Type parameters 96 | 97 | | Name | 98 | | :------ | 99 | | `T` | 100 | 101 | #### Parameters 102 | 103 | | Name | Type | Description | 104 | | :------ | :------ | :------ | 105 | | `query` | `string` | The SQL query to run. | 106 | | `params?` | `QueryParams` | Query params to use. | 107 | 108 | #### Returns 109 | 110 | `Promise` 111 | 112 | An array of matched rows. If none were found an empty array will be returned. 113 | 114 | #### Defined in 115 | 116 | [src/classes/Database.ts:69](https://github.com/BenShelton/library-api/blob/master/packages/core/src/classes/Database.ts#L69) 117 | -------------------------------------------------------------------------------- /docs/core/classes/src.languagemapper.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [src](../modules/src.md) / LanguageMapper 2 | 3 | # Class: LanguageMapper 4 | 5 | [src](../modules/src.md).LanguageMapper 6 | 7 | Maps raw language data to more accessible DTOs. 8 | 9 | ## Table of contents 10 | 11 | ### Constructors 12 | 13 | - [constructor](src.languagemapper.md#constructor) 14 | 15 | ### Methods 16 | 17 | - [MapLanguage](src.languagemapper.md#maplanguage) 18 | - [MapLanguages](src.languagemapper.md#maplanguages) 19 | 20 | ## Constructors 21 | 22 | ### constructor 23 | 24 | • **new LanguageMapper**() 25 | 26 | ## Methods 27 | 28 | ### MapLanguage 29 | 30 | ▸ **MapLanguage**(`language`): [LanguageDTO](../interfaces/types_dto.languagedto.md) 31 | 32 | Maps a raw Language data row to a Language DTO. 33 | 34 | #### Parameters 35 | 36 | | Name | Type | Description | 37 | | :------ | :------ | :------ | 38 | | `language` | [LanguageRow](../interfaces/types_database.languagerow.md) | The data row. | 39 | 40 | #### Returns 41 | 42 | [LanguageDTO](../interfaces/types_dto.languagedto.md) 43 | 44 | #### Defined in 45 | 46 | [src/classes/Mapper.ts:173](https://github.com/BenShelton/library-api/blob/master/packages/core/src/classes/Mapper.ts#L173) 47 | 48 | ___ 49 | 50 | ### MapLanguages 51 | 52 | ▸ **MapLanguages**(`languages`): [LanguageDTO](../interfaces/types_dto.languagedto.md)[] 53 | 54 | Maps multiple Language data rows using [MapLanguage](src.languagemapper.md#maplanguage) and returns the mapped array. 55 | 56 | #### Parameters 57 | 58 | | Name | Type | Description | 59 | | :------ | :------ | :------ | 60 | | `languages` | [LanguageRow](../interfaces/types_database.languagerow.md)[] | The data rows. | 61 | 62 | #### Returns 63 | 64 | [LanguageDTO](../interfaces/types_dto.languagedto.md)[] 65 | 66 | #### Defined in 67 | 68 | [src/classes/Mapper.ts:188](https://github.com/BenShelton/library-api/blob/master/packages/core/src/classes/Mapper.ts#L188) 69 | -------------------------------------------------------------------------------- /docs/core/classes/src.mediacatalogmapper.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [src](../modules/src.md) / MediaCatalogMapper 2 | 3 | # Class: MediaCatalogMapper 4 | 5 | [src](../modules/src.md).MediaCatalogMapper 6 | 7 | Maps Media Catalog database details to more accessible DTOs. 8 | 9 | ## Table of contents 10 | 11 | ### Constructors 12 | 13 | - [constructor](src.mediacatalogmapper.md#constructor) 14 | 15 | ### Methods 16 | 17 | - [MapMediaDetails](src.mediacatalogmapper.md#mapmediadetails) 18 | 19 | ## Constructors 20 | 21 | ### constructor 22 | 23 | • **new MediaCatalogMapper**() 24 | 25 | ## Methods 26 | 27 | ### MapMediaDetails 28 | 29 | ▸ **MapMediaDetails**(`details`): [MediaDetailsDTO](../interfaces/types_dto.mediadetailsdto.md) 30 | 31 | Maps a Media Catalog media details row to a Media Details DTO. 32 | 33 | #### Parameters 34 | 35 | | Name | Type | Description | 36 | | :------ | :------ | :------ | 37 | | `details` | [MediaCatalogItemDTO](../interfaces/types_dto.mediacatalogitemdto.md) | The database row. | 38 | 39 | #### Returns 40 | 41 | [MediaDetailsDTO](../interfaces/types_dto.mediadetailsdto.md) 42 | 43 | #### Defined in 44 | 45 | [src/classes/Mapper.ts:202](https://github.com/BenShelton/library-api/blob/master/packages/core/src/classes/Mapper.ts#L202) 46 | -------------------------------------------------------------------------------- /docs/core/enums/src.publication_classes.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [src](../modules/src.md) / PUBLICATION_CLASSES 2 | 3 | # Enumeration: PUBLICATION\_CLASSES 4 | 5 | [src](../modules/src.md).PUBLICATION_CLASSES 6 | 7 | Integer enums used to refer to certain article types in a publication database. 8 | 9 | ## Table of contents 10 | 11 | ### Enumeration members 12 | 13 | - [OCLM\_WEEK](src.publication_classes.md#oclm_week) 14 | - [WATCHTOWER\_ARTICLE](src.publication_classes.md#watchtower_article) 15 | 16 | ## Enumeration members 17 | 18 | ### OCLM\_WEEK 19 | 20 | • **OCLM\_WEEK** = 106 21 | 22 | #### Defined in 23 | 24 | [src/constants.ts:40](https://github.com/BenShelton/library-api/blob/master/packages/core/src/constants.ts#L40) 25 | 26 | ___ 27 | 28 | ### WATCHTOWER\_ARTICLE 29 | 30 | • **WATCHTOWER\_ARTICLE** = 40 31 | 32 | #### Defined in 33 | 34 | [src/constants.ts:39](https://github.com/BenShelton/library-api/blob/master/packages/core/src/constants.ts#L39) 35 | -------------------------------------------------------------------------------- /docs/core/enums/src.publication_types.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [src](../modules/src.md) / PUBLICATION_TYPES 2 | 3 | # Enumeration: PUBLICATION\_TYPES 4 | 5 | [src](../modules/src.md).PUBLICATION_TYPES 6 | 7 | Integer enums used to refer to certain publication types in the catalog database. 8 | 9 | ## Table of contents 10 | 11 | ### Enumeration members 12 | 13 | - [OCLM](src.publication_types.md#oclm) 14 | - [WATCHTOWER](src.publication_types.md#watchtower) 15 | 16 | ## Enumeration members 17 | 18 | ### OCLM 19 | 20 | • **OCLM** = 30 21 | 22 | #### Defined in 23 | 24 | [src/constants.ts:32](https://github.com/BenShelton/library-api/blob/master/packages/core/src/constants.ts#L32) 25 | 26 | ___ 27 | 28 | ### WATCHTOWER 29 | 30 | • **WATCHTOWER** = 14 31 | 32 | #### Defined in 33 | 34 | [src/constants.ts:31](https://github.com/BenShelton/library-api/blob/master/packages/core/src/constants.ts#L31) 35 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.articlerow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / ArticleRow 2 | 3 | # Interface: ArticleRow 4 | 5 | [types/database](../modules/types_database.md).ArticleRow 6 | 7 | The raw database columns when using an article query. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [ContextTitle](types_database.articlerow.md#contexttitle) 14 | - [DocumentId](types_database.articlerow.md#documentid) 15 | - [Title](types_database.articlerow.md#title) 16 | 17 | ## Properties 18 | 19 | ### ContextTitle 20 | 21 | • **ContextTitle**: `string` 22 | 23 | #### Defined in 24 | 25 | [types/database.d.ts:80](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L80) 26 | 27 | ___ 28 | 29 | ### DocumentId 30 | 31 | • **DocumentId**: `number` 32 | 33 | #### Defined in 34 | 35 | [types/database.d.ts:79](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L79) 36 | 37 | ___ 38 | 39 | ### Title 40 | 41 | • **Title**: `string` 42 | 43 | #### Defined in 44 | 45 | [types/database.d.ts:81](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L81) 46 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.imagerow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / ImageRow 2 | 3 | # Interface: ImageRow 4 | 5 | [types/database](../modules/types_database.md).ImageRow 6 | 7 | The raw database columns when using an image query. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [Caption](types_database.imagerow.md#caption) 14 | - [CategoryType](types_database.imagerow.md#categorytype) 15 | - [ContextTitle](types_database.imagerow.md#contexttitle) 16 | - [FilePath](types_database.imagerow.md#filepath) 17 | - [MultimediaId](types_database.imagerow.md#multimediaid) 18 | 19 | ## Properties 20 | 21 | ### Caption 22 | 23 | • **Caption**: `string` 24 | 25 | #### Defined in 26 | 27 | [types/database.d.ts:19](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L19) 28 | 29 | ___ 30 | 31 | ### CategoryType 32 | 33 | • **CategoryType**: `number` 34 | 35 | #### Defined in 36 | 37 | [types/database.d.ts:24](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L24) 38 | 39 | ___ 40 | 41 | ### ContextTitle 42 | 43 | • **ContextTitle**: `string` 44 | 45 | #### Defined in 46 | 47 | [types/database.d.ts:18](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L18) 48 | 49 | ___ 50 | 51 | ### FilePath 52 | 53 | • **FilePath**: `string` 54 | 55 | The path within the contents directory of a publication to access this image. 56 | 57 | #### Defined in 58 | 59 | [types/database.d.ts:23](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L23) 60 | 61 | ___ 62 | 63 | ### MultimediaId 64 | 65 | • **MultimediaId**: `number` 66 | 67 | #### Defined in 68 | 69 | [types/database.d.ts:17](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L17) 70 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.languagerow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / LanguageRow 2 | 3 | # Interface: LanguageRow 4 | 5 | [types/database](../modules/types_database.md).LanguageRow 6 | 7 | The raw database columns when reading the JSON export of the `Language` table from `mepsunit.db`. 8 | 9 | The export can be found in `data/languages.json`. 10 | 11 | ## Table of contents 12 | 13 | ### Properties 14 | 15 | - [AssociatedTextLanguageId](types_database.languagerow.md#associatedtextlanguageid) 16 | - [EnglishName](types_database.languagerow.md#englishname) 17 | - [IsSignLanguage](types_database.languagerow.md#issignlanguage) 18 | - [IsoAlpha2Code](types_database.languagerow.md#isoalpha2code) 19 | - [IsoAlpha3Code](types_database.languagerow.md#isoalpha3code) 20 | - [IsoName](types_database.languagerow.md#isoname) 21 | - [LanguageId](types_database.languagerow.md#languageid) 22 | - [PrimaryFallbackLanguageId](types_database.languagerow.md#primaryfallbacklanguageid) 23 | - [PrimaryIetfCode](types_database.languagerow.md#primaryietfcode) 24 | - [ScriptId](types_database.languagerow.md#scriptid) 25 | - [Symbol](types_database.languagerow.md#symbol) 26 | - [VernacularName](types_database.languagerow.md#vernacularname) 27 | 28 | ## Properties 29 | 30 | ### AssociatedTextLanguageId 31 | 32 | • **AssociatedTextLanguageId**: `number` 33 | 34 | #### Defined in 35 | 36 | [types/database.d.ts:101](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L101) 37 | 38 | ___ 39 | 40 | ### EnglishName 41 | 42 | • **EnglishName**: `string` 43 | 44 | #### Defined in 45 | 46 | [types/database.d.ts:92](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L92) 47 | 48 | ___ 49 | 50 | ### IsSignLanguage 51 | 52 | • **IsSignLanguage**: `number` 53 | 54 | #### Defined in 55 | 56 | [types/database.d.ts:99](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L99) 57 | 58 | ___ 59 | 60 | ### IsoAlpha2Code 61 | 62 | • **IsoAlpha2Code**: `string` 63 | 64 | #### Defined in 65 | 66 | [types/database.d.ts:95](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L95) 67 | 68 | ___ 69 | 70 | ### IsoAlpha3Code 71 | 72 | • **IsoAlpha3Code**: `string` 73 | 74 | #### Defined in 75 | 76 | [types/database.d.ts:96](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L96) 77 | 78 | ___ 79 | 80 | ### IsoName 81 | 82 | • **IsoName**: `string` 83 | 84 | #### Defined in 85 | 86 | [types/database.d.ts:94](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L94) 87 | 88 | ___ 89 | 90 | ### LanguageId 91 | 92 | • **LanguageId**: `number` 93 | 94 | #### Defined in 95 | 96 | [types/database.d.ts:90](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L90) 97 | 98 | ___ 99 | 100 | ### PrimaryFallbackLanguageId 101 | 102 | • **PrimaryFallbackLanguageId**: `number` 103 | 104 | #### Defined in 105 | 106 | [types/database.d.ts:98](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L98) 107 | 108 | ___ 109 | 110 | ### PrimaryIetfCode 111 | 112 | • **PrimaryIetfCode**: `string` 113 | 114 | #### Defined in 115 | 116 | [types/database.d.ts:97](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L97) 117 | 118 | ___ 119 | 120 | ### ScriptId 121 | 122 | • **ScriptId**: `number` 123 | 124 | #### Defined in 125 | 126 | [types/database.d.ts:100](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L100) 127 | 128 | ___ 129 | 130 | ### Symbol 131 | 132 | • **Symbol**: `string` 133 | 134 | #### Defined in 135 | 136 | [types/database.d.ts:91](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L91) 137 | 138 | ___ 139 | 140 | ### VernacularName 141 | 142 | • **VernacularName**: `string` 143 | 144 | #### Defined in 145 | 146 | [types/database.d.ts:93](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L93) 147 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.mediadetailsrow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / MediaDetailsRow 2 | 3 | # Interface: MediaDetailsRow 4 | 5 | [types/database](../modules/types_database.md).MediaDetailsRow 6 | 7 | The raw database columns when using a media details query. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [Height](types_database.mediadetailsrow.md#height) 14 | - [Id](types_database.mediadetailsrow.md#id) 15 | - [NameFragment](types_database.mediadetailsrow.md#namefragment) 16 | - [Title](types_database.mediadetailsrow.md#title) 17 | - [Width](types_database.mediadetailsrow.md#width) 18 | 19 | ## Properties 20 | 21 | ### Height 22 | 23 | • **Height**: `number` 24 | 25 | #### Defined in 26 | 27 | [types/database.d.ts:35](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L35) 28 | 29 | ___ 30 | 31 | ### Id 32 | 33 | • **Id**: `number` 34 | 35 | #### Defined in 36 | 37 | [types/database.d.ts:31](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L31) 38 | 39 | ___ 40 | 41 | ### NameFragment 42 | 43 | • **NameFragment**: `string` 44 | 45 | #### Defined in 46 | 47 | [types/database.d.ts:33](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L33) 48 | 49 | ___ 50 | 51 | ### Title 52 | 53 | • **Title**: `string` 54 | 55 | #### Defined in 56 | 57 | [types/database.d.ts:32](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L32) 58 | 59 | ___ 60 | 61 | ### Width 62 | 63 | • **Width**: `number` 64 | 65 | #### Defined in 66 | 67 | [types/database.d.ts:34](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L34) 68 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.publicationrow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / PublicationRow 2 | 3 | # Interface: PublicationRow 4 | 5 | [types/database](../modules/types_database.md).PublicationRow 6 | 7 | The raw database columns when using a publication query. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [NameFragment](types_database.publicationrow.md#namefragment) 14 | - [PubMepsLanguageId](types_database.publicationrow.md#pubmepslanguageid) 15 | - [PublicationTypeId](types_database.publicationrow.md#publicationtypeid) 16 | 17 | ## Properties 18 | 19 | ### NameFragment 20 | 21 | • **NameFragment**: `string` 22 | 23 | The filename used on the storage servers and for the internal database of a publication. 24 | 25 | #### Defined in 26 | 27 | [types/database.d.ts:8](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L8) 28 | 29 | ___ 30 | 31 | ### PubMepsLanguageId 32 | 33 | • **PubMepsLanguageId**: `number` 34 | 35 | #### Defined in 36 | 37 | [types/database.d.ts:10](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L10) 38 | 39 | ___ 40 | 41 | ### PublicationTypeId 42 | 43 | • **PublicationTypeId**: `number` 44 | 45 | #### Defined in 46 | 47 | [types/database.d.ts:9](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L9) 48 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.relatedpublicationrow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / RelatedPublicationRow 2 | 3 | # Interface: RelatedPublicationRow 4 | 5 | [types/database](../modules/types_database.md).RelatedPublicationRow 6 | 7 | The raw database columns when using a relation publications query. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [RefBeginParagraphOrdinal](types_database.relatedpublicationrow.md#refbeginparagraphordinal) 14 | - [RefEndParagraphOrdinal](types_database.relatedpublicationrow.md#refendparagraphordinal) 15 | - [RefMepsDocumentId](types_database.relatedpublicationrow.md#refmepsdocumentid) 16 | 17 | ## Properties 18 | 19 | ### RefBeginParagraphOrdinal 20 | 21 | • **RefBeginParagraphOrdinal**: ``null`` \| `number` 22 | 23 | #### Defined in 24 | 25 | [types/database.d.ts:109](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L109) 26 | 27 | ___ 28 | 29 | ### RefEndParagraphOrdinal 30 | 31 | • **RefEndParagraphOrdinal**: ``null`` \| `number` 32 | 33 | #### Defined in 34 | 35 | [types/database.d.ts:110](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L110) 36 | 37 | ___ 38 | 39 | ### RefMepsDocumentId 40 | 41 | • **RefMepsDocumentId**: `number` 42 | 43 | #### Defined in 44 | 45 | [types/database.d.ts:108](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L108) 46 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.videorowbase.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / VideoRowBase 2 | 3 | # Interface: VideoRowBase 4 | 5 | [types/database](../modules/types_database.md).VideoRowBase 6 | 7 | ## Hierarchy 8 | 9 | - **VideoRowBase** 10 | 11 | ↳ [VideoRowPub](types_database.videorowpub.md) 12 | 13 | ↳ [VideoRowDoc](types_database.videorowdoc.md) 14 | 15 | ## Table of contents 16 | 17 | ### Properties 18 | 19 | - [IssueTagNumber](types_database.videorowbase.md#issuetagnumber) 20 | - [MultimediaId](types_database.videorowbase.md#multimediaid) 21 | - [Track](types_database.videorowbase.md#track) 22 | 23 | ## Properties 24 | 25 | ### IssueTagNumber 26 | 27 | • **IssueTagNumber**: `number` 28 | 29 | Will be `0` if no issue exists. 30 | 31 | #### Defined in 32 | 33 | [types/database.d.ts:44](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L44) 34 | 35 | ___ 36 | 37 | ### MultimediaId 38 | 39 | • **MultimediaId**: `number` 40 | 41 | #### Defined in 42 | 43 | [types/database.d.ts:39](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L39) 44 | 45 | ___ 46 | 47 | ### Track 48 | 49 | • **Track**: `number` 50 | 51 | #### Defined in 52 | 53 | [types/database.d.ts:40](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L40) 54 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.videorowdoc.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / VideoRowDoc 2 | 3 | # Interface: VideoRowDoc 4 | 5 | [types/database](../modules/types_database.md).VideoRowDoc 6 | 7 | The raw database columns when using a video query that returns a `doc` type video. 8 | 9 | ## Hierarchy 10 | 11 | - [VideoRowBase](types_database.videorowbase.md) 12 | 13 | ↳ **VideoRowDoc** 14 | 15 | ## Table of contents 16 | 17 | ### Properties 18 | 19 | - [IssueTagNumber](types_database.videorowdoc.md#issuetagnumber) 20 | - [KeySymbol](types_database.videorowdoc.md#keysymbol) 21 | - [MepsDocumentId](types_database.videorowdoc.md#mepsdocumentid) 22 | - [MultimediaId](types_database.videorowdoc.md#multimediaid) 23 | - [Track](types_database.videorowdoc.md#track) 24 | 25 | ## Properties 26 | 27 | ### IssueTagNumber 28 | 29 | • **IssueTagNumber**: `number` 30 | 31 | Will be `0` if no issue exists. 32 | 33 | #### Inherited from 34 | 35 | [VideoRowBase](types_database.videorowbase.md).[IssueTagNumber](types_database.videorowbase.md#issuetagnumber) 36 | 37 | #### Defined in 38 | 39 | [types/database.d.ts:44](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L44) 40 | 41 | ___ 42 | 43 | ### KeySymbol 44 | 45 | • **KeySymbol**: ``null`` 46 | 47 | #### Defined in 48 | 49 | [types/database.d.ts:59](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L59) 50 | 51 | ___ 52 | 53 | ### MepsDocumentId 54 | 55 | • **MepsDocumentId**: `number` 56 | 57 | #### Defined in 58 | 59 | [types/database.d.ts:60](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L60) 60 | 61 | ___ 62 | 63 | ### MultimediaId 64 | 65 | • **MultimediaId**: `number` 66 | 67 | #### Inherited from 68 | 69 | [VideoRowBase](types_database.videorowbase.md).[MultimediaId](types_database.videorowbase.md#multimediaid) 70 | 71 | #### Defined in 72 | 73 | [types/database.d.ts:39](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L39) 74 | 75 | ___ 76 | 77 | ### Track 78 | 79 | • **Track**: `number` 80 | 81 | #### Inherited from 82 | 83 | [VideoRowBase](types_database.videorowbase.md).[Track](types_database.videorowbase.md#track) 84 | 85 | #### Defined in 86 | 87 | [types/database.d.ts:40](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L40) 88 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_database.videorowpub.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/database](../modules/types_database.md) / VideoRowPub 2 | 3 | # Interface: VideoRowPub 4 | 5 | [types/database](../modules/types_database.md).VideoRowPub 6 | 7 | The raw database columns when using a video query that returns a `pub` type video. 8 | 9 | ## Hierarchy 10 | 11 | - [VideoRowBase](types_database.videorowbase.md) 12 | 13 | ↳ **VideoRowPub** 14 | 15 | ## Table of contents 16 | 17 | ### Properties 18 | 19 | - [IssueTagNumber](types_database.videorowpub.md#issuetagnumber) 20 | - [KeySymbol](types_database.videorowpub.md#keysymbol) 21 | - [MepsDocumentId](types_database.videorowpub.md#mepsdocumentid) 22 | - [MultimediaId](types_database.videorowpub.md#multimediaid) 23 | - [Track](types_database.videorowpub.md#track) 24 | 25 | ## Properties 26 | 27 | ### IssueTagNumber 28 | 29 | • **IssueTagNumber**: `number` 30 | 31 | Will be `0` if no issue exists. 32 | 33 | #### Inherited from 34 | 35 | [VideoRowBase](types_database.videorowbase.md).[IssueTagNumber](types_database.videorowbase.md#issuetagnumber) 36 | 37 | #### Defined in 38 | 39 | [types/database.d.ts:44](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L44) 40 | 41 | ___ 42 | 43 | ### KeySymbol 44 | 45 | • **KeySymbol**: `string` 46 | 47 | #### Defined in 48 | 49 | [types/database.d.ts:51](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L51) 50 | 51 | ___ 52 | 53 | ### MepsDocumentId 54 | 55 | • **MepsDocumentId**: ``null`` 56 | 57 | #### Defined in 58 | 59 | [types/database.d.ts:52](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L52) 60 | 61 | ___ 62 | 63 | ### MultimediaId 64 | 65 | • **MultimediaId**: `number` 66 | 67 | #### Inherited from 68 | 69 | [VideoRowBase](types_database.videorowbase.md).[MultimediaId](types_database.videorowbase.md#multimediaid) 70 | 71 | #### Defined in 72 | 73 | [types/database.d.ts:39](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L39) 74 | 75 | ___ 76 | 77 | ### Track 78 | 79 | • **Track**: `number` 80 | 81 | #### Inherited from 82 | 83 | [VideoRowBase](types_database.videorowbase.md).[Track](types_database.videorowbase.md#track) 84 | 85 | #### Defined in 86 | 87 | [types/database.d.ts:40](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L40) 88 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_dto.imagedto.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/dto](../modules/types_dto.md) / ImageDTO 2 | 3 | # Interface: ImageDTO 4 | 5 | [types/dto](../modules/types_dto.md).ImageDTO 6 | 7 | The returned information when mapping raw image data. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [caption](types_dto.imagedto.md#caption) 14 | - [categoryType](types_dto.imagedto.md#categorytype) 15 | - [contentsPath](types_dto.imagedto.md#contentspath) 16 | - [filePath](types_dto.imagedto.md#filepath) 17 | - [filename](types_dto.imagedto.md#filename) 18 | - [id](types_dto.imagedto.md#id) 19 | - [languageId](types_dto.imagedto.md#languageid) 20 | 21 | ## Properties 22 | 23 | ### caption 24 | 25 | • **caption**: `string` 26 | 27 | The description in the database for this image. 28 | 29 | #### Defined in 30 | 31 | [types/dto.d.ts:18](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L18) 32 | 33 | ___ 34 | 35 | ### categoryType 36 | 37 | • **categoryType**: `number` 38 | 39 | The internal category type. Known types are: 40 | - 8 = Article image (Normally displayed) 41 | - 9 = Article cover image (Not normally displayed) 42 | - 15 = Publication cover image (Not normally displayed) 43 | 44 | #### Defined in 45 | 46 | [types/dto.d.ts:33](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L33) 47 | 48 | ___ 49 | 50 | ### contentsPath 51 | 52 | • **contentsPath**: `string` 53 | 54 | The path to access the publication itself. 55 | 56 | #### Defined in 57 | 58 | [types/dto.d.ts:26](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L26) 59 | 60 | ___ 61 | 62 | ### filePath 63 | 64 | • **filePath**: `string` 65 | 66 | The path to access the image within the downloaded publication. 67 | 68 | #### Defined in 69 | 70 | [types/dto.d.ts:22](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L22) 71 | 72 | ___ 73 | 74 | ### filename 75 | 76 | • **filename**: `string` 77 | 78 | The filename of the image. 79 | 80 | #### Defined in 81 | 82 | [types/dto.d.ts:14](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L14) 83 | 84 | ___ 85 | 86 | ### id 87 | 88 | • **id**: `string` 89 | 90 | A unique id not related to the database. 91 | 92 | #### Defined in 93 | 94 | [types/dto.d.ts:10](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L10) 95 | 96 | ___ 97 | 98 | ### languageId 99 | 100 | • **languageId**: `number` 101 | 102 | The Meps Language Id of this image. 103 | 104 | #### Defined in 105 | 106 | [types/dto.d.ts:37](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L37) 107 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_dto.languagedto.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/dto](../modules/types_dto.md) / LanguageDTO 2 | 3 | # Interface: LanguageDTO 4 | 5 | [types/dto](../modules/types_dto.md).LanguageDTO 6 | 7 | Information returned when requesting a language. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [englishName](types_dto.languagedto.md#englishname) 14 | - [id](types_dto.languagedto.md#id) 15 | - [signLanguage](types_dto.languagedto.md#signlanguage) 16 | - [symbol](types_dto.languagedto.md#symbol) 17 | - [vernacularName](types_dto.languagedto.md#vernacularname) 18 | 19 | ## Properties 20 | 21 | ### englishName 22 | 23 | • **englishName**: `string` 24 | 25 | The English name for the language, e.g. `Spanish` for Spanish. 26 | 27 | #### Defined in 28 | 29 | [types/dto.d.ts:115](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L115) 30 | 31 | ___ 32 | 33 | ### id 34 | 35 | • **id**: `number` 36 | 37 | The Meps Language Id. 38 | 39 | #### Defined in 40 | 41 | [types/dto.d.ts:107](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L107) 42 | 43 | ___ 44 | 45 | ### signLanguage 46 | 47 | • **signLanguage**: `boolean` 48 | 49 | Indicates whether this is a sign language. 50 | Sign languages do not use publications so are generally unsupported. 51 | 52 | #### Defined in 53 | 54 | [types/dto.d.ts:124](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L124) 55 | 56 | ___ 57 | 58 | ### symbol 59 | 60 | • **symbol**: `string` 61 | 62 | The unique language Symbol. 63 | 64 | #### Defined in 65 | 66 | [types/dto.d.ts:111](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L111) 67 | 68 | ___ 69 | 70 | ### vernacularName 71 | 72 | • **vernacularName**: `string` 73 | 74 | The language name as displayed in that language, e.g. `español` for Spanish. 75 | 76 | #### Defined in 77 | 78 | [types/dto.d.ts:119](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L119) 79 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_dto.mediacatalogdatabasedto.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/dto](../modules/types_dto.md) / MediaCatalogDatabaseDTO 2 | 3 | # Interface: MediaCatalogDatabaseDTO 4 | 5 | [types/dto](../modules/types_dto.md).MediaCatalogDatabaseDTO 6 | 7 | An object representation of the Media Catalog NDJSON file. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [mediaItems](types_dto.mediacatalogdatabasedto.md#mediaitems) 14 | - [version](types_dto.mediacatalogdatabasedto.md#version) 15 | 16 | ## Properties 17 | 18 | ### mediaItems 19 | 20 | • **mediaItems**: [MediaCatalogItemDTO](types_dto.mediacatalogitemdto.md)[] 21 | 22 | A list of media items in this catalog. 23 | 24 | #### Defined in 25 | 26 | [types/dto.d.ts:201](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L201) 27 | 28 | ___ 29 | 30 | ### version 31 | 32 | • **version**: `number` 33 | 34 | The version of the catalog. 35 | 36 | #### Defined in 37 | 38 | [types/dto.d.ts:190](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L190) 39 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_dto.mediacatalogitemdto.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/dto](../modules/types_dto.md) / MediaCatalogItemDTO 2 | 3 | # Interface: MediaCatalogItemDTO 4 | 5 | [types/dto](../modules/types_dto.md).MediaCatalogItemDTO 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [doc](types_dto.mediacatalogitemdto.md#doc) 12 | - [duration](types_dto.mediacatalogitemdto.md#duration) 13 | - [format](types_dto.mediacatalogitemdto.md#format) 14 | - [id](types_dto.mediacatalogitemdto.md#id) 15 | - [image](types_dto.mediacatalogitemdto.md#image) 16 | - [imageSqr](types_dto.mediacatalogitemdto.md#imagesqr) 17 | - [issue](types_dto.mediacatalogitemdto.md#issue) 18 | - [key](types_dto.mediacatalogitemdto.md#key) 19 | - [languageAgnosticId](types_dto.mediacatalogitemdto.md#languageagnosticid) 20 | - [title](types_dto.mediacatalogitemdto.md#title) 21 | - [track](types_dto.mediacatalogitemdto.md#track) 22 | 23 | ## Properties 24 | 25 | ### doc 26 | 27 | • **doc**: `string` \| `number` 28 | 29 | Either the `docID` or `pubSymbol` depending on the kind of media. 30 | 31 | #### Defined in 32 | 33 | [types/dto.d.ts:139](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L139) 34 | 35 | ___ 36 | 37 | ### duration 38 | 39 | • **duration**: `number` 40 | 41 | Duration in seconds. Also includes millisecond precision. 42 | 43 | #### Defined in 44 | 45 | [types/dto.d.ts:172](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L172) 46 | 47 | ___ 48 | 49 | ### format 50 | 51 | • **format**: ``"VIDEO"`` \| ``"AUDIO"`` 52 | 53 | Either `'VIDEO'` or `'AUDIO'`. 54 | 55 | #### Defined in 56 | 57 | [types/dto.d.ts:160](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L160) 58 | 59 | ___ 60 | 61 | ### id 62 | 63 | • **id**: `string` 64 | 65 | A unique id for this item among all languages. 66 | 67 | #### Defined in 68 | 69 | [types/dto.d.ts:135](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L135) 70 | 71 | ___ 72 | 73 | ### image 74 | 75 | • **image**: `string` 76 | 77 | A URL of the highest quality image for this media. 78 | 79 | #### Defined in 80 | 81 | [types/dto.d.ts:176](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L176) 82 | 83 | ___ 84 | 85 | ### imageSqr 86 | 87 | • **imageSqr**: `string` 88 | 89 | A URL of the highest quality square image for this media. 90 | 91 | #### Defined in 92 | 93 | [types/dto.d.ts:180](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L180) 94 | 95 | ___ 96 | 97 | ### issue 98 | 99 | • `Optional` **issue**: `string` 100 | 101 | An optional issue, this is a similar format to other instances of `issue` just shorter. 102 | 103 | **`example`** 104 | // equivalent 105 | video.issue: 20210500 106 | detail.issueDate: '202105' 107 | 108 | // equivalent missing issue 109 | video.issue: 0 110 | detail.issueDate: undefined 111 | 112 | #### Defined in 113 | 114 | [types/dto.d.ts:156](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L156) 115 | 116 | ___ 117 | 118 | ### key 119 | 120 | • **key**: `string` 121 | 122 | The `primaryCategory` which correlates to `key` in other areas. 123 | 124 | #### Defined in 125 | 126 | [types/dto.d.ts:164](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L164) 127 | 128 | ___ 129 | 130 | ### languageAgnosticId 131 | 132 | • **languageAgnosticId**: `string` 133 | 134 | An id that can be used to identify the same item in a different language's media catalog. 135 | 136 | #### Defined in 137 | 138 | [types/dto.d.ts:131](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L131) 139 | 140 | ___ 141 | 142 | ### title 143 | 144 | • **title**: `string` 145 | 146 | The displayed title for this media. 147 | 148 | #### Defined in 149 | 150 | [types/dto.d.ts:168](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L168) 151 | 152 | ___ 153 | 154 | ### track 155 | 156 | • **track**: `number` 157 | 158 | The track number. 159 | 160 | #### Defined in 161 | 162 | [types/dto.d.ts:143](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L143) 163 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_dto.mediadetailsdto.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/dto](../modules/types_dto.md) / MediaDetailsDTO 2 | 3 | # Interface: MediaDetailsDTO 4 | 5 | [types/dto](../modules/types_dto.md).MediaDetailsDTO 6 | 7 | The returned information when mapping raw media details data. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [caption](types_dto.mediadetailsdto.md#caption) 14 | - [filename](types_dto.mediadetailsdto.md#filename) 15 | - [height](types_dto.mediadetailsdto.md#height) 16 | - [id](types_dto.mediadetailsdto.md#id) 17 | - [url](types_dto.mediadetailsdto.md#url) 18 | - [width](types_dto.mediadetailsdto.md#width) 19 | 20 | ## Properties 21 | 22 | ### caption 23 | 24 | • **caption**: `string` 25 | 26 | #### Defined in 27 | 28 | [types/dto.d.ts:80](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L80) 29 | 30 | ___ 31 | 32 | ### filename 33 | 34 | • **filename**: `string` 35 | 36 | #### Defined in 37 | 38 | [types/dto.d.ts:79](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L79) 39 | 40 | ___ 41 | 42 | ### height 43 | 44 | • **height**: `number` 45 | 46 | **`deprecated`** Is no longer available since the switch to media catalogs. 47 | 48 | The height in pixels of the image. 49 | 50 | #### Defined in 51 | 52 | [types/dto.d.ts:92](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L92) 53 | 54 | ___ 55 | 56 | ### id 57 | 58 | • **id**: `string` 59 | 60 | A unique id not related to the database. 61 | 62 | #### Defined in 63 | 64 | [types/dto.d.ts:78](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L78) 65 | 66 | ___ 67 | 68 | ### url 69 | 70 | • **url**: `string` 71 | 72 | The URL of the image on the external media server. 73 | Can be used as a `src` for an `img` element or downloaded. 74 | 75 | #### Defined in 76 | 77 | [types/dto.d.ts:97](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L97) 78 | 79 | ___ 80 | 81 | ### width 82 | 83 | • **width**: `number` 84 | 85 | **`deprecated`** Is no longer available since the switch to media catalogs. 86 | 87 | The width in pixels of the image. 88 | 89 | #### Defined in 90 | 91 | [types/dto.d.ts:86](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L86) 92 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_dto.relatedpublicationdto.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/dto](../modules/types_dto.md) / RelatedPublicationDTO 2 | 3 | # Interface: RelatedPublicationDTO 4 | 5 | [types/dto](../modules/types_dto.md).RelatedPublicationDTO 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [beginParagraph](types_dto.relatedpublicationdto.md#beginparagraph) 12 | - [endParagraph](types_dto.relatedpublicationdto.md#endparagraph) 13 | - [id](types_dto.relatedpublicationdto.md#id) 14 | 15 | ## Properties 16 | 17 | ### beginParagraph 18 | 19 | • **beginParagraph**: ``null`` \| `number` 20 | 21 | #### Defined in 22 | 23 | [types/dto.d.ts:212](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L212) 24 | 25 | ___ 26 | 27 | ### endParagraph 28 | 29 | • **endParagraph**: ``null`` \| `number` 30 | 31 | #### Defined in 32 | 33 | [types/dto.d.ts:216](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L216) 34 | 35 | ___ 36 | 37 | ### id 38 | 39 | • **id**: `number` 40 | 41 | The Meps Document Id. 42 | 43 | #### Defined in 44 | 45 | [types/dto.d.ts:208](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L208) 46 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_dto.videodto.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/dto](../modules/types_dto.md) / VideoDTO 2 | 3 | # Interface: VideoDTO 4 | 5 | [types/dto](../modules/types_dto.md).VideoDTO 6 | 7 | The returned information when mapping raw video data. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [doc](types_dto.videodto.md#doc) 14 | - [filename](types_dto.videodto.md#filename) 15 | - [id](types_dto.videodto.md#id) 16 | - [issue](types_dto.videodto.md#issue) 17 | - [languageId](types_dto.videodto.md#languageid) 18 | - [track](types_dto.videodto.md#track) 19 | - [type](types_dto.videodto.md#type) 20 | 21 | ## Properties 22 | 23 | ### doc 24 | 25 | • **doc**: `string` \| `number` 26 | 27 | #### Defined in 28 | 29 | [types/dto.d.ts:56](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L56) 30 | 31 | ___ 32 | 33 | ### filename 34 | 35 | • **filename**: `string` 36 | 37 | A filename. Purely informational. 38 | 39 | #### Defined in 40 | 41 | [types/dto.d.ts:51](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L51) 42 | 43 | ___ 44 | 45 | ### id 46 | 47 | • **id**: `string` 48 | 49 | A unique id not related to the database. 50 | 51 | #### Defined in 52 | 53 | [types/dto.d.ts:47](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L47) 54 | 55 | ___ 56 | 57 | ### issue 58 | 59 | • **issue**: `number` 60 | 61 | Either an issue date stored as a number, or `0` if irrelevant. 62 | 63 | **`example`** 64 | 20210500 65 | 66 | #### Defined in 67 | 68 | [types/dto.d.ts:64](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L64) 69 | 70 | ___ 71 | 72 | ### languageId 73 | 74 | • **languageId**: `number` 75 | 76 | The Meps Language Id of this video. 77 | 78 | #### Defined in 79 | 80 | [types/dto.d.ts:68](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L68) 81 | 82 | ___ 83 | 84 | ### track 85 | 86 | • **track**: `number` 87 | 88 | #### Defined in 89 | 90 | [types/dto.d.ts:57](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L57) 91 | 92 | ___ 93 | 94 | ### type 95 | 96 | • **type**: ``"pub"`` \| ``"doc"`` 97 | 98 | Affects how information is retrieved about this video (for example in getting details or the video stream) 99 | 100 | #### Defined in 101 | 102 | [types/dto.d.ts:55](https://github.com/BenShelton/library-api/blob/master/packages/core/types/dto.d.ts#L55) 103 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_hag.getmediapublinks.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/hag](../modules/types_hag.md) / GetMediaPubLinks 2 | 3 | # Interface: GetMediaPubLinks 4 | 5 | [types/hag](../modules/types_hag.md).GetMediaPubLinks 6 | 7 | The returned data when requesting a video from the external Media API endpoint. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [booknum](types_hag.getmediapublinks.md#booknum) 14 | - [files](types_hag.getmediapublinks.md#files) 15 | - [formattedDate](types_hag.getmediapublinks.md#formatteddate) 16 | - [issue](types_hag.getmediapublinks.md#issue) 17 | - [languages](types_hag.getmediapublinks.md#languages) 18 | - [parentPubName](types_hag.getmediapublinks.md#parentpubname) 19 | - [pub](types_hag.getmediapublinks.md#pub) 20 | - [pubImage](types_hag.getmediapublinks.md#pubimage) 21 | - [pubName](types_hag.getmediapublinks.md#pubname) 22 | - [specialty](types_hag.getmediapublinks.md#specialty) 23 | - [track](types_hag.getmediapublinks.md#track) 24 | 25 | ## Properties 26 | 27 | ### booknum 28 | 29 | • **booknum**: ``null`` 30 | 31 | #### Defined in 32 | 33 | [types/hag.d.ts:48](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L48) 34 | 35 | ___ 36 | 37 | ### files 38 | 39 | • **files**: `Object` 40 | 41 | #### Index signature 42 | 43 | ▪ [key: `string`]: { `MP4`: [MediaPubLink](types_hag.mediapublink.md)[] } 44 | 45 | #### Defined in 46 | 47 | [types/hag.d.ts:66](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L66) 48 | 49 | ___ 50 | 51 | ### formattedDate 52 | 53 | • **formattedDate**: `string`[] 54 | 55 | #### Defined in 56 | 57 | [types/hag.d.ts:51](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L51) 58 | 59 | ___ 60 | 61 | ### issue 62 | 63 | • **issue**: `string` 64 | 65 | #### Defined in 66 | 67 | [types/hag.d.ts:50](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L50) 68 | 69 | ___ 70 | 71 | ### languages 72 | 73 | • **languages**: `Object` 74 | 75 | #### Index signature 76 | 77 | ▪ [key: `string`]: { `direction`: `string` ; `locale`: `string` ; `name`: `string` } 78 | 79 | #### Defined in 80 | 81 | [types/hag.d.ts:59](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L59) 82 | 83 | ___ 84 | 85 | ### parentPubName 86 | 87 | • **parentPubName**: `string` 88 | 89 | #### Defined in 90 | 91 | [types/hag.d.ts:47](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L47) 92 | 93 | ___ 94 | 95 | ### pub 96 | 97 | • **pub**: `string` 98 | 99 | #### Defined in 100 | 101 | [types/hag.d.ts:49](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L49) 102 | 103 | ___ 104 | 105 | ### pubImage 106 | 107 | • **pubImage**: `Object` 108 | 109 | #### Type declaration 110 | 111 | | Name | Type | 112 | | :------ | :------ | 113 | | `checksum` | ``null`` | 114 | | `modifiedDatetime` | `string` | 115 | | `url` | `string` | 116 | 117 | #### Defined in 118 | 119 | [types/hag.d.ts:54](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L54) 120 | 121 | ___ 122 | 123 | ### pubName 124 | 125 | • **pubName**: `string` 126 | 127 | #### Defined in 128 | 129 | [types/hag.d.ts:46](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L46) 130 | 131 | ___ 132 | 133 | ### specialty 134 | 135 | • **specialty**: `string` 136 | 137 | #### Defined in 138 | 139 | [types/hag.d.ts:53](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L53) 140 | 141 | ___ 142 | 143 | ### track 144 | 145 | • **track**: `number` 146 | 147 | #### Defined in 148 | 149 | [types/hag.d.ts:52](https://github.com/BenShelton/library-api/blob/master/packages/core/types/hag.d.ts#L52) 150 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.catalogschemaversionrow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / CatalogSchemaVersionRow 2 | 3 | # Interface: CatalogSchemaVersionRow 4 | 5 | [types/media](../modules/types_media.md).CatalogSchemaVersionRow 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [o](types_media.catalogschemaversionrow.md#o) 12 | - [type](types_media.catalogschemaversionrow.md#type) 13 | 14 | ## Properties 15 | 16 | ### o 17 | 18 | • **o**: `number` 19 | 20 | The Media Catalog version. 21 | 22 | #### Defined in 23 | 24 | [types/media.d.ts:20](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L20) 25 | 26 | ___ 27 | 28 | ### type 29 | 30 | • **type**: ``"catalogSchemaVersion"`` 31 | 32 | #### Defined in 33 | 34 | [types/media.d.ts:16](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L16) 35 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.categoryrow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / CategoryRow 2 | 3 | # Interface: CategoryRow 4 | 5 | [types/media](../modules/types_media.md).CategoryRow 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [o](types_media.categoryrow.md#o) 12 | - [type](types_media.categoryrow.md#type) 13 | 14 | ## Properties 15 | 16 | ### o 17 | 18 | • **o**: [CategoryRowObj](../modules/types_media.md#categoryrowobj) 19 | 20 | #### Defined in 21 | 22 | [types/media.d.ts:112](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L112) 23 | 24 | ___ 25 | 26 | ### type 27 | 28 | • **type**: ``"category"`` 29 | 30 | #### Defined in 31 | 32 | [types/media.d.ts:111](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L111) 33 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.categoryrowobjcontainer.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / CategoryRowObjContainer 2 | 3 | # Interface: CategoryRowObjContainer 4 | 5 | [types/media](../modules/types_media.md).CategoryRowObjContainer 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [images](types_media.categoryrowobjcontainer.md#images) 12 | - [media](types_media.categoryrowobjcontainer.md#media) 13 | - [type](types_media.categoryrowobjcontainer.md#type) 14 | 15 | ## Properties 16 | 17 | ### images 18 | 19 | • **images**: `Object` 20 | 21 | #### Type declaration 22 | 23 | | Name | Type | 24 | | :------ | :------ | 25 | | `pnr` | `Object` | 26 | | `pnr.lg` | `string` | 27 | | `pnr.md` | `string` | 28 | | `pnr.sm` | `string` | 29 | | `pnr.xs` | `string` | 30 | 31 | #### Defined in 32 | 33 | [types/media.d.ts:94](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L94) 34 | 35 | ___ 36 | 37 | ### media 38 | 39 | • **media**: `string`[] 40 | 41 | A list of `naturalKey` values that can be used to link to a [MediaItemRow](types_media.mediaitemrow.md). 42 | 43 | #### Defined in 44 | 45 | [types/media.d.ts:105](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L105) 46 | 47 | ___ 48 | 49 | ### type 50 | 51 | • **type**: ``"ondemand"`` 52 | 53 | Signifies this page is a list of media. 54 | 55 | The media available is under `media`. 56 | 57 | #### Defined in 58 | 59 | [types/media.d.ts:93](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L93) 60 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.categoryrowobjondemand.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / CategoryRowObjOnDemand 2 | 3 | # Interface: CategoryRowObjOnDemand 4 | 5 | [types/media](../modules/types_media.md).CategoryRowObjOnDemand 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [key](types_media.categoryrowobjondemand.md#key) 12 | - [name](types_media.categoryrowobjondemand.md#name) 13 | - [subcategories](types_media.categoryrowobjondemand.md#subcategories) 14 | - [type](types_media.categoryrowobjondemand.md#type) 15 | 16 | ## Properties 17 | 18 | ### key 19 | 20 | • **key**: `string` 21 | 22 | #### Defined in 23 | 24 | [types/media.d.ts:79](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L79) 25 | 26 | ___ 27 | 28 | ### name 29 | 30 | • **name**: `string` 31 | 32 | #### Defined in 33 | 34 | [types/media.d.ts:80](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L80) 35 | 36 | ___ 37 | 38 | ### subcategories 39 | 40 | • **subcategories**: [CategoryRowObj](../modules/types_media.md#categoryrowobj)[] 41 | 42 | Nested "pages" of categories. 43 | 44 | #### Defined in 45 | 46 | [types/media.d.ts:84](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L84) 47 | 48 | ___ 49 | 50 | ### type 51 | 52 | • **type**: ``"container"`` 53 | 54 | Signifies this "page" of categories is a list of more categories. 55 | 56 | The nested categories are under `subcategories`. 57 | 58 | #### Defined in 59 | 60 | [types/media.d.ts:78](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L78) 61 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.imagesizes.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / ImageSizes 2 | 3 | # Interface: ImageSizes 4 | 5 | [types/media](../modules/types_media.md).ImageSizes 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [lg](types_media.imagesizes.md#lg) 12 | - [md](types_media.imagesizes.md#md) 13 | - [sm](types_media.imagesizes.md#sm) 14 | - [xl](types_media.imagesizes.md#xl) 15 | - [xs](types_media.imagesizes.md#xs) 16 | 17 | ## Properties 18 | 19 | ### lg 20 | 21 | • **lg**: `string` 22 | 23 | The complete URL to this image on the publication servers. 24 | Large size. 25 | 26 | #### Defined in 27 | 28 | [types/media.d.ts:43](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L43) 29 | 30 | ___ 31 | 32 | ### md 33 | 34 | • **md**: `string` 35 | 36 | The complete URL to this image on the publication servers. 37 | Medium size. 38 | 39 | #### Defined in 40 | 41 | [types/media.d.ts:38](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L38) 42 | 43 | ___ 44 | 45 | ### sm 46 | 47 | • **sm**: `string` 48 | 49 | The complete URL to this image on the publication servers. 50 | Small size. 51 | 52 | #### Defined in 53 | 54 | [types/media.d.ts:33](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L33) 55 | 56 | ___ 57 | 58 | ### xl 59 | 60 | • `Optional` **xl**: `string` 61 | 62 | The complete URL to this image on the publication servers. 63 | Extra large size. 64 | 65 | Isn't always available. If not use `lg` instead. 66 | 67 | #### Defined in 68 | 69 | [types/media.d.ts:50](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L50) 70 | 71 | ___ 72 | 73 | ### xs 74 | 75 | • **xs**: `string` 76 | 77 | The complete URL to this image on the publication servers. 78 | Extra small size. 79 | 80 | #### Defined in 81 | 82 | [types/media.d.ts:28](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L28) 83 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.languagerow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / LanguageRow 2 | 3 | # Interface: LanguageRow 4 | 5 | [types/media](../modules/types_media.md).LanguageRow 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [o](types_media.languagerow.md#o) 12 | - [type](types_media.languagerow.md#type) 13 | 14 | ## Properties 15 | 16 | ### o 17 | 18 | • **o**: `Object` 19 | 20 | Details about the language being used in this Media Catalog. 21 | 22 | #### Type declaration 23 | 24 | | Name | Type | Description | 25 | | :------ | :------ | :------ | 26 | | `code` | `string` | Corresponds to `Symbol` of [LanguageDTO](types_dto.languagedto.md). | 27 | | `isLangPair` | `boolean` | - | 28 | | `isRTL` | `boolean` | - | 29 | | `isSignLanguage` | `boolean` | - | 30 | | `locale` | `string` | - | 31 | | `name` | `string` | - | 32 | | `vernacular` | `string` | - | 33 | 34 | #### Defined in 35 | 36 | [types/media.d.ts:58](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L58) 37 | 38 | ___ 39 | 40 | ### type 41 | 42 | • **type**: ``"language"`` 43 | 44 | #### Defined in 45 | 46 | [types/media.d.ts:54](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L54) 47 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.mediacatalogctor.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / MediaCatalogCtor 2 | 3 | # Interface: MediaCatalogCtor 4 | 5 | [types/media](../modules/types_media.md).MediaCatalogCtor 6 | 7 | Constructor params for {@link MediaCatalog} class. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [languageId](types_media.mediacatalogctor.md#languageid) 14 | - [path](types_media.mediacatalogctor.md#path) 15 | 16 | ## Properties 17 | 18 | ### languageId 19 | 20 | • **languageId**: `number` 21 | 22 | The Meps Language Id of this publication. 23 | 24 | #### Defined in 25 | 26 | [types/media.d.ts:12](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L12) 27 | 28 | ___ 29 | 30 | ### path 31 | 32 | • **path**: `string` 33 | 34 | The path to the downloaded Media Catalog. 35 | 36 | #### Defined in 37 | 38 | [types/media.d.ts:8](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L8) 39 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.mediaitemrow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / MediaItemRow 2 | 3 | # Interface: MediaItemRow 4 | 5 | [types/media](../modules/types_media.md).MediaItemRow 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [o](types_media.mediaitemrow.md#o) 12 | - [type](types_media.mediaitemrow.md#type) 13 | 14 | ## Properties 15 | 16 | ### o 17 | 18 | • **o**: `Object` 19 | 20 | #### Type declaration 21 | 22 | | Name | Type | Description | 23 | | :------ | :------ | :------ | 24 | | `checksums` | `string`[] | - | 25 | | `duration` | `number` | Duration in seconds. Also includes millisecond precision. | 26 | | `firstPublished` | `string` | ISO Date string. | 27 | | `images` | `Object` | - | 28 | | `images.lsr?` | [ImageSizes](types_media.imagesizes.md) | Widescreen (16:9) images. | 29 | | `images.sqr?` | [ImageSizes](types_media.imagesizes.md) | Square images. You probably want `lsr` instead. | 30 | | `keyParts` | { `formatCode`: ``"VIDEO"`` \| ``"AUDIO"`` ; `languageCode`: `string` ; `track`: `number` } & { `docID`: `number` } & { `formatCode`: ``"VIDEO"`` \| ``"AUDIO"`` ; `languageCode`: `string` ; `track`: `number` } & { `issueDate?`: `string` ; `pubSymbol`: `string` } | - | 31 | | `languageAgnosticNaturalKey` | `string` | The same as `naturalKey` but without the language. Possibly used to find the same media in a different language's Media Catalog. | 32 | | `naturalKey` | `string` | An Id of sorts, used within category rows as a reference. | 33 | | `primaryCategory` | `string` | Refers to the `key` of a [CategoryRowObj](../modules/types_media.md#categoryrowobj). | 34 | | `title` | `string` | The displayed title. | 35 | 36 | #### Defined in 37 | 38 | [types/media.d.ts:117](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L117) 39 | 40 | ___ 41 | 42 | ### type 43 | 44 | • **type**: ``"media-item"`` 45 | 46 | #### Defined in 47 | 48 | [types/media.d.ts:116](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L116) 49 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_media.signaturerow.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/media](../modules/types_media.md) / SignatureRow 2 | 3 | # Interface: SignatureRow 4 | 5 | [types/media](../modules/types_media.md).SignatureRow 6 | 7 | ## Table of contents 8 | 9 | ### Properties 10 | 11 | - [o](types_media.signaturerow.md#o) 12 | - [type](types_media.signaturerow.md#type) 13 | 14 | ## Properties 15 | 16 | ### o 17 | 18 | • **o**: `string` 19 | 20 | A hash of some sort. 21 | 22 | #### Defined in 23 | 24 | [types/media.d.ts:189](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L189) 25 | 26 | ___ 27 | 28 | ### type 29 | 30 | • **type**: ``"signature"`` 31 | 32 | #### Defined in 33 | 34 | [types/media.d.ts:185](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L185) 35 | -------------------------------------------------------------------------------- /docs/core/interfaces/types_publication.publicationctor.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / [types/publication](../modules/types_publication.md) / PublicationCtor 2 | 3 | # Interface: PublicationCtor 4 | 5 | [types/publication](../modules/types_publication.md).PublicationCtor 6 | 7 | Constructor params for [Publication](../classes/src.publication.md) class. 8 | 9 | ## Table of contents 10 | 11 | ### Properties 12 | 13 | - [dir](types_publication.publicationctor.md#dir) 14 | - [filename](types_publication.publicationctor.md#filename) 15 | - [languageId](types_publication.publicationctor.md#languageid) 16 | - [type](types_publication.publicationctor.md#type) 17 | 18 | ## Properties 19 | 20 | ### dir 21 | 22 | • **dir**: `string` 23 | 24 | The directory where the publication is located. 25 | 26 | **`example`** 'downloads/publications' 27 | 28 | #### Defined in 29 | 30 | [types/publication.d.ts:25](https://github.com/BenShelton/library-api/blob/master/packages/core/types/publication.d.ts#L25) 31 | 32 | ___ 33 | 34 | ### filename 35 | 36 | • **filename**: `string` 37 | 38 | The filename of the downloaded publication. 39 | This must be the NameFragment as it is used the internal database too. 40 | 41 | **`example`** 'w_E_202012' 42 | 43 | #### Defined in 44 | 45 | [types/publication.d.ts:19](https://github.com/BenShelton/library-api/blob/master/packages/core/types/publication.d.ts#L19) 46 | 47 | ___ 48 | 49 | ### languageId 50 | 51 | • `Optional` **languageId**: `number` 52 | 53 | The Meps Language Id of this publication. 54 | 55 | **`default`** 0 (English) 56 | 57 | #### Defined in 58 | 59 | [types/publication.d.ts:35](https://github.com/BenShelton/library-api/blob/master/packages/core/types/publication.d.ts#L35) 60 | 61 | ___ 62 | 63 | ### type 64 | 65 | • **type**: [PublicationType](../modules/types_publication.md#publicationtype) 66 | 67 | **`see`** PublicationType 68 | 69 | #### Defined in 70 | 71 | [types/publication.d.ts:29](https://github.com/BenShelton/library-api/blob/master/packages/core/types/publication.d.ts#L29) 72 | -------------------------------------------------------------------------------- /docs/core/modules/types_database.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / types/database 2 | 3 | # Module: types/database 4 | 5 | ## Table of contents 6 | 7 | ### Interfaces 8 | 9 | - [ArticleRow](../interfaces/types_database.articlerow.md) 10 | - [ImageRow](../interfaces/types_database.imagerow.md) 11 | - [LanguageRow](../interfaces/types_database.languagerow.md) 12 | - [MediaDetailsRow](../interfaces/types_database.mediadetailsrow.md) 13 | - [PublicationRow](../interfaces/types_database.publicationrow.md) 14 | - [RelatedPublicationRow](../interfaces/types_database.relatedpublicationrow.md) 15 | - [VideoRowBase](../interfaces/types_database.videorowbase.md) 16 | - [VideoRowDoc](../interfaces/types_database.videorowdoc.md) 17 | - [VideoRowPub](../interfaces/types_database.videorowpub.md) 18 | 19 | ### Type aliases 20 | 21 | - [DocumentMediaRow](types_database.md#documentmediarow) 22 | - [VideoRow](types_database.md#videorow) 23 | 24 | ## Type aliases 25 | 26 | ### DocumentMediaRow 27 | 28 | Ƭ **DocumentMediaRow**: [ImageRow](../interfaces/types_database.imagerow.md) & { `DataType`: ``0`` } \| [VideoRow](types_database.md#videorow) & { `DataType`: ``2`` \| ``3`` } 29 | 30 | Either an image or video row based on `DataType`. 31 | 32 | #### Defined in 33 | 34 | [types/database.d.ts:71](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L71) 35 | 36 | ___ 37 | 38 | ### VideoRow 39 | 40 | Ƭ **VideoRow**: [VideoRowPub](../interfaces/types_database.videorowpub.md) \| [VideoRowDoc](../interfaces/types_database.videorowdoc.md) 41 | 42 | A union of the raw database columns when using a video query that returns any type video. 43 | 44 | #### Defined in 45 | 46 | [types/database.d.ts:66](https://github.com/BenShelton/library-api/blob/master/packages/core/types/database.d.ts#L66) 47 | -------------------------------------------------------------------------------- /docs/core/modules/types_dto.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / types/dto 2 | 3 | # Module: types/dto 4 | 5 | ## Table of contents 6 | 7 | ### Interfaces 8 | 9 | - [ImageDTO](../interfaces/types_dto.imagedto.md) 10 | - [LanguageDTO](../interfaces/types_dto.languagedto.md) 11 | - [MediaCatalogDatabaseDTO](../interfaces/types_dto.mediacatalogdatabasedto.md) 12 | - [MediaCatalogItemDTO](../interfaces/types_dto.mediacatalogitemdto.md) 13 | - [MediaDetailsDTO](../interfaces/types_dto.mediadetailsdto.md) 14 | - [RelatedPublicationDTO](../interfaces/types_dto.relatedpublicationdto.md) 15 | - [VideoDTO](../interfaces/types_dto.videodto.md) 16 | -------------------------------------------------------------------------------- /docs/core/modules/types_hag.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / types/hag 2 | 3 | # Module: types/hag 4 | 5 | ## Table of contents 6 | 7 | ### Interfaces 8 | 9 | - [GetMediaPubLinks](../interfaces/types_hag.getmediapublinks.md) 10 | - [MediaPubLink](../interfaces/types_hag.mediapublink.md) 11 | -------------------------------------------------------------------------------- /docs/core/modules/types_media.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / types/media 2 | 3 | # Module: types/media 4 | 5 | ## Table of contents 6 | 7 | ### Interfaces 8 | 9 | - [CatalogSchemaVersionRow](../interfaces/types_media.catalogschemaversionrow.md) 10 | - [CategoryRow](../interfaces/types_media.categoryrow.md) 11 | - [CategoryRowObjContainer](../interfaces/types_media.categoryrowobjcontainer.md) 12 | - [CategoryRowObjOnDemand](../interfaces/types_media.categoryrowobjondemand.md) 13 | - [ImageSizes](../interfaces/types_media.imagesizes.md) 14 | - [LanguageRow](../interfaces/types_media.languagerow.md) 15 | - [MediaCatalogCtor](../interfaces/types_media.mediacatalogctor.md) 16 | - [MediaItemRow](../interfaces/types_media.mediaitemrow.md) 17 | - [SignatureRow](../interfaces/types_media.signaturerow.md) 18 | 19 | ### Type aliases 20 | 21 | - [CategoryRowObj](types_media.md#categoryrowobj) 22 | - [MediaCatalogRow](types_media.md#mediacatalogrow) 23 | 24 | ## Type aliases 25 | 26 | ### CategoryRowObj 27 | 28 | Ƭ **CategoryRowObj**: [CategoryRowObjOnDemand](../interfaces/types_media.categoryrowobjondemand.md) \| [CategoryRowObjContainer](../interfaces/types_media.categoryrowobjcontainer.md) 29 | 30 | #### Defined in 31 | 32 | [types/media.d.ts:108](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L108) 33 | 34 | ___ 35 | 36 | ### MediaCatalogRow 37 | 38 | Ƭ **MediaCatalogRow**: [CatalogSchemaVersionRow](../interfaces/types_media.catalogschemaversionrow.md) \| [LanguageRow](../interfaces/types_media.languagerow.md) \| [CategoryRow](../interfaces/types_media.categoryrow.md) \| [MediaItemRow](../interfaces/types_media.mediaitemrow.md) \| [SignatureRow](../interfaces/types_media.signaturerow.md) 39 | 40 | A row of the Media Catalog NDJSON file. 41 | 42 | Rows can have different structures and are identified using `type`. 43 | 44 | #### Defined in 45 | 46 | [types/media.d.ts:197](https://github.com/BenShelton/library-api/blob/master/packages/core/types/media.d.ts#L197) 47 | -------------------------------------------------------------------------------- /docs/core/modules/types_publication.md: -------------------------------------------------------------------------------- 1 | [Library Core](../README.md) / types/publication 2 | 3 | # Module: types/publication 4 | 5 | ## Table of contents 6 | 7 | ### Interfaces 8 | 9 | - [PublicationCtor](../interfaces/types_publication.publicationctor.md) 10 | 11 | ### Type aliases 12 | 13 | - [PublicationType](types_publication.md#publicationtype) 14 | 15 | ## Type aliases 16 | 17 | ### PublicationType 18 | 19 | Ƭ **PublicationType**: ``"wt"`` \| ``"oclm"`` \| ``"other"`` 20 | 21 | The types of publications that can be accessed. 22 | - `wt`: Watchtower 23 | - `oclm`: Our Christian Life & Ministry Workbook 24 | - `other`: Any other publication 25 | 26 | #### Defined in 27 | 28 | [types/publication.d.ts:7](https://github.com/BenShelton/library-api/blob/master/packages/core/types/publication.d.ts#L7) 29 | -------------------------------------------------------------------------------- /docs/express/README.md: -------------------------------------------------------------------------------- 1 | # Library Express 2 | 3 | TODO: Write Documentation 4 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Home 2 | 3 | Welcome to Library API Documentation. 4 | 5 | ## Packages 6 | 7 | Select a package below to view documentation for that package. 8 | 9 | - [Library Media](./media/) 10 | - [Library Express](./express/) 11 | - [Library Core](./core/) 12 | -------------------------------------------------------------------------------- /jest.config.base.ts: -------------------------------------------------------------------------------- 1 | import { Config } from '@jest/types' 2 | 3 | const config: Config.InitialOptions = { 4 | globals: { 5 | 'ts-jest': { 6 | tsconfig: 'test/tsconfig.json' 7 | } 8 | }, 9 | moduleFileExtensions: [ 10 | 'ts', 11 | 'js' 12 | ], 13 | transform: { 14 | '^.+\\.ts$': 'ts-jest' 15 | }, 16 | testMatch: [ 17 | '/test/**/*.spec.ts' 18 | ], 19 | testEnvironment: 'node', 20 | collectCoverageFrom: [ 21 | '/src/**/*.ts' 22 | ] 23 | } 24 | 25 | export default config 26 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.11.0", 3 | "npmClient": "yarn", 4 | "packages": [ 5 | "packages/*" 6 | ], 7 | "command": { 8 | "publish": { 9 | "allowBranch": [ 10 | "master" 11 | ], 12 | "ignoreChanges": [ 13 | "*.md" 14 | ], 15 | "verifyAccess": false, 16 | "conventionalCommits": true, 17 | "message": "chore(release): publish %s" 18 | } 19 | }, 20 | "useWorkspaces": true 21 | } 22 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'packages/core/**/*.{js,ts}': [ 3 | 'yarn core lint:fix', 4 | () => 'yarn core tsc', 5 | 'yarn core test:staged', 6 | () => 'yarn core docs', 7 | 'git add docs' 8 | ], 9 | 'packages/express/**/*.{js,ts}': [ 10 | 'yarn express lint:fix', 11 | () => 'yarn express tsc', 12 | 'yarn express test:staged' 13 | ], 14 | 'packages/media/**/*.{js,ts,vue}': [ 15 | 'yarn media lint:fix', 16 | () => 'yarn media tsc', 17 | 'yarn media test:staged' 18 | ], 19 | './*.{js,ts}': [ 20 | 'yarn lint:root --fix' 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "library-api", 3 | "private": true, 4 | "workspaces": { 5 | "packages": [ 6 | "packages/*" 7 | ], 8 | "nohoist": [ 9 | "**/electron", 10 | "**/electron/**" 11 | ] 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/BenShelton/library-api" 16 | }, 17 | "scripts": { 18 | "prepare": "husky install", 19 | "bootstrap": "yarn install && lerna bootstrap && yarn build", 20 | "build": "lerna run build --parallel", 21 | "clean": "lerna clean -y", 22 | "lint": "lerna run lint --parallel", 23 | "lint:root": "eslint ./*.{js,ts}", 24 | "test": "lerna run test --parallel", 25 | "test:ci": "yarn lint:root && lerna run test:ci --parallel", 26 | "tsc": "lerna run tsc --parallel", 27 | "docs": "lerna run docs --parallel", 28 | "core": "yarn workspace @library-api/core", 29 | "express": "yarn workspace @library-api/express", 30 | "media": "yarn workspace @library-api/media" 31 | }, 32 | "devDependencies": { 33 | "@commitlint/cli": "^12.1.4", 34 | "@commitlint/config-conventional": "^12.1.4", 35 | "@types/jest": "^26.0.23", 36 | "@types/node": "^14.15.4", 37 | "@typescript-eslint/eslint-plugin": "^4.27.0", 38 | "@typescript-eslint/parser": "^4.27.0", 39 | "commitizen": "^4.2.4", 40 | "cz-conventional-changelog": "^3.3.0", 41 | "eslint": "^7.29.0", 42 | "eslint-config-standard": "^16.0.3", 43 | "eslint-plugin-import": "^2.23.4", 44 | "eslint-plugin-jest": "^24.3.6", 45 | "eslint-plugin-node": "^11.1.0", 46 | "eslint-plugin-promise": "^5.1.0", 47 | "gh-release": "^6.0.0", 48 | "husky": "^6.0.0", 49 | "jest": "^27.0.4", 50 | "lerna": "^4.0.0", 51 | "lint-staged": "^11.0.0", 52 | "ts-jest": "^27.0.3", 53 | "ts-node": "^10.0.0", 54 | "tsc-watch": "^4.4.0", 55 | "typedoc": "^0.21.0", 56 | "typedoc-plugin-markdown": "^3.10.0", 57 | "typescript": "^4.3.4", 58 | "vls": "^0.7.4" 59 | }, 60 | "license": "MIT", 61 | "engines": { 62 | "node": "^14", 63 | "yarn": "^1.22" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/core/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../.eslintrc.js') 2 | 3 | /** 4 | * @type { import('eslint').Linter.Config } 5 | */ 6 | module.exports = { 7 | ...baseConfig 8 | } 9 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 |

2 | Library Core 3 |

4 | 5 |

6 | 7 | NPM Version 8 | 9 | 10 | Package Size 11 | 12 |

13 | 14 |

15 | Core tools for use with other Library API packages. 16 |

17 | 18 |
19 | 20 | ## Description 21 | 22 | These can also be used to build your own app based on this API. 23 | 24 | This package is brought to you by [Library API](../../README.md). 25 | 26 | ## Installing 27 | 28 | Please note that core tools are built to run on a Node environment as it requires a filesystem to store downloaded files. 29 | 30 | You can install with your preferred package manager: 31 | 32 | ```bash 33 | # NPM 34 | npm install @library-api/core 35 | 36 | # Yarn 37 | yarn add @library-api/core 38 | ``` 39 | 40 | ## Documentation 41 | 42 | View the documentation [here](https://benshelton.github.io/library-api/core/) 43 | 44 | ## Development 45 | 46 | Run the following commands to get started. If you are running from the root directory you can add `media` to run these (for example `yarn core build` instead of just `yarn build`): 47 | 48 | ```bash 49 | # Build (outputs to /dist) 50 | yarn build 51 | 52 | # Lint files 53 | yarn lint 54 | 55 | # Run test suite 56 | yarn test 57 | 58 | # Run Type Checking Service 59 | yarn tsc 60 | ``` 61 | -------------------------------------------------------------------------------- /packages/core/jest.config.ts: -------------------------------------------------------------------------------- 1 | import { Config } from '@jest/types' 2 | import { pathsToModuleNameMapper } from 'ts-jest/utils' 3 | 4 | import baseConfig from '../../jest.config.base' 5 | import { compilerOptions } from './test/tsconfig.json' 6 | 7 | const config: Config.InitialOptions = { 8 | ...baseConfig, 9 | 10 | moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '/' }) 11 | } 12 | 13 | export default config 14 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@library-api/core", 3 | "version": "0.11.0", 4 | "description": "Core tools for use with @library-api packages.", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "files": [ 8 | "dist", 9 | "types" 10 | ], 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/BenShelton/library-api", 17 | "directory": "packages/core" 18 | }, 19 | "scripts": { 20 | "build": "tsc --build tsconfig.json", 21 | "lint": "eslint . --ext .js,.ts", 22 | "lint:fix": "yarn lint --fix", 23 | "test": "jest --config=jest.config.ts", 24 | "test:bail": "yarn test --bail", 25 | "test:coverage": "yarn test --coverage", 26 | "test:ci": "yarn lint && yarn tsc && yarn test:bail", 27 | "test:watch": "yarn test --watch-all -t", 28 | "test:staged": "yarn test --bail --findRelatedTests", 29 | "tsc": "tsc --noEmit", 30 | "docs": "typedoc" 31 | }, 32 | "dependencies": { 33 | "node-fetch": "^2.6.1", 34 | "sqlite": "^4.0.23", 35 | "sqlite3": "^5.0.2", 36 | "unzipper": "^0.10.11" 37 | }, 38 | "devDependencies": { 39 | "@types/node-fetch": "^2.5.10", 40 | "@types/sqlite3": "^3.1.7", 41 | "@types/unzipper": "^0.10.3" 42 | }, 43 | "author": { 44 | "name": "BenShelton", 45 | "email": "bensheltonjones@gmail.com" 46 | }, 47 | "keywords": [ 48 | "jw", 49 | "media", 50 | "library", 51 | "meetings", 52 | "publications", 53 | "api", 54 | "core" 55 | ], 56 | "license": "MIT" 57 | } 58 | -------------------------------------------------------------------------------- /packages/core/src/catalog.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path' 2 | 3 | import { downloadCatalog, downloadMediaCatalog } from './download' 4 | import { getLanguageById } from './language' 5 | import { checkExists } from './utils' 6 | import { MediaCatalog } from './classes/Media' 7 | 8 | /** 9 | * @todo Check for latest version, currently just checks existence of file. 10 | * 11 | * Checks whether the currently downloaded catalog is the latest version & updates it if not. 12 | * 13 | * @param path The path to download the catalog to. 14 | * 15 | * @returns `true` if the catalog was updated, `false` if it was already the latest version. 16 | */ 17 | export async function updateCatalog (path: string): Promise { 18 | const exists = await checkExists(path) 19 | if (!exists) { 20 | await downloadCatalog(path) 21 | return true 22 | } 23 | return false 24 | } 25 | 26 | /** 27 | * @todo Check for latest version, currently just checks existence of file. 28 | * 29 | * Retrieves a media catalog file and returns a {@link MediaCatalog} instance if it exists. 30 | * Will download the file if it is not yet downloaded. 31 | * 32 | * @param dir The directory where media catalogs are to be stored. 33 | * @param languageId The Meps Language Id to use. 34 | * 35 | * @returns A {@link MediaCatalog} if it exists, `null` if not found. 36 | */ 37 | export async function getMediaCatalog (dir: string, languageId: number): Promise { 38 | const language = getLanguageById(languageId) 39 | if (!language) return null 40 | const code = language.symbol 41 | const path = join(dir, `media-catalog-${code}.ndjson`) 42 | const exists = await checkExists(path) 43 | if (!exists) { 44 | try { 45 | await downloadMediaCatalog(code, path) 46 | } catch (err) { 47 | return null 48 | } 49 | } 50 | return new MediaCatalog({ path, languageId }) 51 | } 52 | -------------------------------------------------------------------------------- /packages/core/src/classes/Media.ts: -------------------------------------------------------------------------------- 1 | import { MediaCatalogMapper } from './Mapper' 2 | import { readLines } from '../utils' 3 | import { SONG_PUBLICATION } from '../constants' 4 | 5 | import { MediaDetailsDTO, MediaCatalogDatabaseDTO } from '../../types/dto' 6 | import { MediaCatalogCtor, MediaCatalogRow } from '../../types/media' 7 | 8 | export class MediaCatalog { 9 | private _database: MediaCatalogDatabaseDTO | null = null 10 | private _mapper: MediaCatalogMapper 11 | path: string 12 | languageId: number 13 | 14 | /** 15 | * @param {Object} ctor See {@link MediaCatalogCtor} 16 | */ 17 | constructor ({ path, languageId }: MediaCatalogCtor) { 18 | this.path = path 19 | this.languageId = languageId 20 | this._mapper = new MediaCatalogMapper() 21 | } 22 | 23 | /** 24 | * Loads the media catalog from the NDJSON file and transforms it into an object that is easier to work with 25 | * 26 | * Will cache the loaded database so subsequent calls will be quicker. 27 | */ 28 | async getDatabase (): Promise { 29 | if (this._database) return this._database 30 | const newDatabase: MediaCatalogDatabaseDTO = { 31 | version: 0, 32 | categories: [], 33 | mediaItems: [] 34 | } 35 | await readLines(this.path, line => { 36 | const json: MediaCatalogRow = JSON.parse(line) 37 | switch (json.type) { 38 | case 'catalogSchemaVersion': 39 | newDatabase.version = json.o 40 | break 41 | case 'category': 42 | newDatabase.categories.push(json.o) 43 | break 44 | case 'media-item': { 45 | const details = json.o 46 | const { lsr, sqr } = details.images 47 | newDatabase.mediaItems.push({ 48 | languageAgnosticId: details.languageAgnosticNaturalKey, 49 | id: details.naturalKey, 50 | doc: 'docID' in details.keyParts ? details.keyParts.docID : details.keyParts.pubSymbol, 51 | issue: 'issueDate' in details.keyParts ? details.keyParts.issueDate : undefined, 52 | track: details.keyParts.track, 53 | format: details.keyParts.formatCode, 54 | key: details.primaryCategory, 55 | title: details.title, 56 | duration: details.duration, 57 | image: lsr ? (lsr.xl || lsr.lg || lsr.md || lsr.sm || lsr.xs) : '', 58 | imageSqr: sqr ? (sqr.xl || sqr.lg || sqr.md || sqr.sm || sqr.xs) : '' 59 | }) 60 | } 61 | } 62 | }) 63 | this._database = newDatabase 64 | return newDatabase 65 | } 66 | 67 | /** 68 | * Retrieves information about a video from the media catalog. 69 | * The video details found within a publication's database contain limited information about the video itself. 70 | * Most of this information is contained within a separate file which is divided per language. 71 | * 72 | * This method allows passing in the video returned from the publication to get more details from the media catalog. 73 | * The returned image will be of the highest quality available (biggest size). 74 | * 75 | * @param video Pass in a returned {@link VideoDTO} from another method, see example. 76 | * 77 | * @returns MediaDetails if they exist, `null` if they are not found. 78 | * 79 | * @example 80 | * ```ts 81 | * const video = publication.getVideo(...) 82 | * const details = await mediaCatalog.getMediaDetails(video) 83 | * ``` 84 | */ 85 | async getMediaDetails ({ doc, issue, track }: { doc: string | number, issue: string | number, track: string | number }): Promise { 86 | const db = await this.getDatabase() 87 | const issueNum = Number(issue || 0) 88 | const detailIssue = issueNum ? String(issueNum).substr(0, 6) : null 89 | const details = db.mediaItems.find(item => { 90 | if (detailIssue) { 91 | if (detailIssue !== item.issue) return false 92 | } 93 | if (typeof item.doc === 'number') { 94 | if (item.doc !== +doc) return false 95 | } else { 96 | if (item.doc !== String(doc)) return false 97 | } 98 | if (item.track !== +track) return false 99 | 100 | return true 101 | }) 102 | if (!details) return null 103 | return this._mapper.MapMediaDetails(details) 104 | } 105 | 106 | /** 107 | * Retrieves the video MediaDetails of a chosen song number. 108 | * 109 | * @param track The number of the track. 110 | * 111 | * @returns MediaDetails if they exist, `null` if they are not found. 112 | */ 113 | async getSongDetails (track: number): Promise { 114 | return this.getMediaDetails({ ...SONG_PUBLICATION, track }) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /packages/core/src/classes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Database' 2 | export * from './Mapper' 3 | export * from './Publication' 4 | -------------------------------------------------------------------------------- /packages/core/src/constants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The URL used as a base for downloading publications. 3 | * 4 | * This is the site hosting most of the files. 5 | */ 6 | export const PUBLICATION_URL = 'https://download-a.akamaihd.net' 7 | 8 | /** 9 | * The URL of the current catalog. 10 | */ 11 | export const CATALOG_URL = `${PUBLICATION_URL}/meps/jwl/current/catalogs/v3/catalog.db.gz` as const 12 | 13 | /** 14 | * The URL used as for checking media options. 15 | * 16 | * This returns a list of options of download qualities based on the passed in params. 17 | */ 18 | export const MEDIA_URL = 'https://api.hag27.com/GETPUBMEDIALINKS' 19 | 20 | /** 21 | * The URL of all the media catalogs. 22 | * 23 | * These are NDJSON files that list images and other metadata used for media found within publications. 24 | */ 25 | export const MEDIA_CATALOGS_URL = 'https://app.jw-cdn.org/catalogs/media' 26 | 27 | /** 28 | * Integer enums used to refer to certain publication types in the catalog database. 29 | */ 30 | export enum PUBLICATION_TYPES { 31 | WATCHTOWER = 14, 32 | OCLM = 30 33 | } 34 | 35 | /** 36 | * Integer enums used to refer to certain article types in a publication database. 37 | */ 38 | export enum PUBLICATION_CLASSES { 39 | WATCHTOWER_ARTICLE = 40, 40 | OCLM_WEEK = 106 41 | } 42 | 43 | /** 44 | * Params for the current songbook publication, without the track. 45 | * 46 | * Used internally to provide methods which only require a track in order to retrieve a song. 47 | */ 48 | export const SONG_PUBLICATION = { 49 | type: 'pub', 50 | doc: 'sjjm', 51 | issue: 0 52 | } as const 53 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './classes' 2 | 3 | export * from './catalog' 4 | export * from './constants' 5 | export * from './download' 6 | export * from './language' 7 | export * from './utils' 8 | -------------------------------------------------------------------------------- /packages/core/src/language.ts: -------------------------------------------------------------------------------- 1 | import { LanguageMapper } from './classes' 2 | import languages from './data/languages.json' 3 | 4 | import { LanguageDTO } from '../types/dto' 5 | 6 | /** 7 | * Retrieves a list of all languages currently supported. 8 | * 9 | * @returns An array of languages. 10 | */ 11 | export function getLanguages (): LanguageDTO[] { 12 | return new LanguageMapper().MapLanguages(languages) 13 | } 14 | 15 | /** 16 | * Searches for the specified language based on the provided id. 17 | * 18 | * @param id The Meps Language Id to search for. 19 | * 20 | * @returns The language if it was found, `null` if it does not exist. 21 | */ 22 | export function getLanguageById (id: number): LanguageDTO | null { 23 | const language = languages.find(l => l.LanguageId === id) 24 | if (!language) return null 25 | return new LanguageMapper().MapLanguage(language) 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { constants, createReadStream } from 'fs' 2 | import { mkdir, rm, access } from 'fs/promises' 3 | import { createInterface } from 'readline' 4 | 5 | /** 6 | * Creates the specified directory. Will create parent directories if missing. 7 | * 8 | * @param dir The directory to create. 9 | */ 10 | export function createDir (dir: string): Promise { 11 | return mkdir(dir, { recursive: true }) 12 | } 13 | 14 | /** 15 | * Removes the entire specified directory, similar to `rm -rf {dir}`. 16 | * 17 | * @param dir The directory to remove. 18 | */ 19 | export function emptyDir (dir: string): Promise { 20 | return rm(dir, { recursive: true, force: true }) 21 | } 22 | 23 | /** 24 | * Checks if a file exists. 25 | * 26 | * @param path The path to the file. 27 | * @returns `true` if the file exists, `false` if it does not. 28 | */ 29 | export async function checkExists (path: string): Promise { 30 | try { 31 | await access(path, constants.F_OK) 32 | return true 33 | } catch (err) { 34 | return false 35 | } 36 | } 37 | 38 | /** 39 | * Reads a file line by line and allows running a callback for each line. 40 | * 41 | * @param path The path to the file. 42 | * @param cb The callback to apply for each line. 43 | */ 44 | export async function readLines (path: string, cb: (line: string) => void): Promise { 45 | const stream = createReadStream(path) 46 | const rl = createInterface({ 47 | input: stream, 48 | crlfDelay: Infinity 49 | }) 50 | for await (const line of rl) { 51 | if (line) cb(line) 52 | } 53 | } 54 | 55 | /** 56 | * Validates that the passed in `date` is a string of `yyyy-mm-dd` format. 57 | * 58 | * @param date The date to validate. 59 | * @returns `true` if the date is valid, `false` if not. 60 | */ 61 | export function isValidDate (date: unknown): date is string { 62 | if (!date) return false 63 | if (typeof date !== 'string') return false 64 | if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return false 65 | return true 66 | } 67 | -------------------------------------------------------------------------------- /packages/core/test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: '../.eslintrc.js', 3 | plugins: [ 4 | 'jest' 5 | ], 6 | env: { 7 | 'jest/globals': true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/core/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "baseUrl": "../", 6 | "rootDir": "../", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "types": [ 13 | "node", 14 | "jest" 15 | ] 16 | }, 17 | "include": [ 18 | ".", 19 | "../src" 20 | ], 21 | "exclude": [] 22 | } 23 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "importHelpers": false, 8 | "tsBuildInfoFile": "dist/.tsbuildinfo", 9 | "resolveJsonModule": true 10 | }, 11 | "include": [ 12 | "src/**/*.ts", 13 | "src/**/*.json" 14 | ], 15 | "exclude": [ 16 | "**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/core/typedoc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type { import("typedoc").TypeDocOptions } 3 | */ 4 | module.exports = { 5 | name: 'Library Core', 6 | entryPoints: [ 7 | 'src/index.ts', 8 | 'types' 9 | ], 10 | out: '../../docs/core', 11 | plugin: 'typedoc-plugin-markdown', 12 | excludePrivate: true, 13 | excludeInternal: true, 14 | readme: 'none', 15 | gitRevision: 'master' 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/types/database.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The raw database columns when using a publication query. 3 | */ 4 | export interface PublicationRow { 5 | /** 6 | * The filename used on the storage servers and for the internal database of a publication. 7 | */ 8 | NameFragment: string 9 | PublicationTypeId: number 10 | PubMepsLanguageId: number 11 | } 12 | 13 | /** 14 | * The raw database columns when using an image query. 15 | */ 16 | export interface ImageRow { 17 | MultimediaId: number 18 | ContextTitle: string 19 | Caption: string 20 | /** 21 | * The path within the contents directory of a publication to access this image. 22 | */ 23 | FilePath: string 24 | CategoryType: number 25 | } 26 | 27 | /** 28 | * The raw database columns when using a media details query. 29 | */ 30 | export interface MediaDetailsRow { 31 | Id: number 32 | Title: string 33 | NameFragment: string 34 | Width: number 35 | Height: number 36 | } 37 | 38 | interface VideoRowBase { 39 | MultimediaId: number 40 | Track: number 41 | /** 42 | * Will be `0` if no issue exists. 43 | */ 44 | IssueTagNumber: number 45 | } 46 | 47 | /** 48 | * The raw database columns when using a video query that returns a `pub` type video. 49 | */ 50 | export interface VideoRowPub extends VideoRowBase { 51 | KeySymbol: string 52 | MepsDocumentId: null 53 | } 54 | 55 | /** 56 | * The raw database columns when using a video query that returns a `doc` type video. 57 | */ 58 | export interface VideoRowDoc extends VideoRowBase { 59 | KeySymbol: null 60 | MepsDocumentId: number 61 | } 62 | 63 | /** 64 | * A union of the raw database columns when using a video query that returns any type video. 65 | */ 66 | export type VideoRow = VideoRowPub | VideoRowDoc 67 | 68 | /** 69 | * Either an image or video row based on `DataType`. 70 | */ 71 | export type DocumentMediaRow = 72 | | (ImageRow & { DataType: 0 }) 73 | | (VideoRow & { DataType: 2 | 3 }) 74 | 75 | /** 76 | * The raw database columns when using an article query. 77 | */ 78 | export interface ArticleRow { 79 | DocumentId: number 80 | ContextTitle: string 81 | Title: string 82 | } 83 | 84 | /** 85 | * The raw database columns when reading the JSON export of the `Language` table from `mepsunit.db`. 86 | * 87 | * The export can be found in `data/languages.json`. 88 | */ 89 | export interface LanguageRow { 90 | LanguageId: number 91 | Symbol: string 92 | EnglishName: string 93 | VernacularName: string 94 | IsoName: string 95 | IsoAlpha2Code: string 96 | IsoAlpha3Code: string 97 | PrimaryIetfCode: string 98 | PrimaryFallbackLanguageId: number 99 | IsSignLanguage: number 100 | ScriptId: number 101 | AssociatedTextLanguageId: number 102 | } 103 | 104 | /** 105 | * The raw database columns when using a relation publications query. 106 | */ 107 | interface RelatedPublicationRow { 108 | RefMepsDocumentId: number 109 | RefBeginParagraphOrdinal: number | null 110 | RefEndParagraphOrdinal: number | null 111 | } 112 | -------------------------------------------------------------------------------- /packages/core/types/hag.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * One of the returned links when requesting a video from the external Media API endpoint. 3 | * 4 | * These types may not be extensive but include what we need. 5 | */ 6 | interface MediaPubLink { 7 | title: string 8 | file: { 9 | url: string 10 | stream: string 11 | modifiedDatetime: string 12 | checksum: string 13 | } 14 | filesize: number 15 | trackImage: { 16 | url: string 17 | modifiedDatetime: string 18 | checksum: null 19 | } 20 | markers: null 21 | label: '240p' | '480p' | '720p' 22 | track: number 23 | hasTrack: boolean 24 | pub: string 25 | docid: number 26 | booknum: number 27 | mimetype: string 28 | edition: string 29 | editionDescr: string 30 | format: string 31 | formatDescr: string 32 | specialty: string 33 | specialtyDescr: string 34 | subtitled: boolean 35 | frameWidth: number 36 | frameHeight: number 37 | frameRate: number 38 | duration: number 39 | bitRate: number 40 | } 41 | 42 | /** 43 | * The returned data when requesting a video from the external Media API endpoint. 44 | */ 45 | export interface GetMediaPubLinks { 46 | pubName: string 47 | parentPubName: string 48 | booknum: null 49 | pub: string 50 | issue: string 51 | formattedDate: string[] 52 | track: number 53 | specialty: string 54 | pubImage: { 55 | url: string 56 | modifiedDatetime: string 57 | checksum: null 58 | } 59 | languages: { 60 | [key: string]: { 61 | name: string 62 | direction: string 63 | locale: string 64 | } 65 | } 66 | files: { 67 | [key: string]: { 68 | MP4: MediaPubLink[] 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/core/types/publication.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The types of publications that can be accessed. 3 | * - `wt`: Watchtower 4 | * - `oclm`: Our Christian Life & Ministry Workbook 5 | * - `other`: Any other publication 6 | */ 7 | export type PublicationType = 'wt' | 'oclm' | 'other' 8 | 9 | /** 10 | * Constructor params for {@link Publication} class. 11 | */ 12 | export interface PublicationCtor { 13 | /** 14 | * The filename of the downloaded publication. 15 | * This must be the NameFragment as it is used the internal database too. 16 | * 17 | * @example 'w_E_202012' 18 | */ 19 | filename: string 20 | /** 21 | * The directory where the publication is located. 22 | * 23 | * @example 'downloads/publications' 24 | */ 25 | dir: string 26 | /** 27 | * @see PublicationType 28 | */ 29 | type: PublicationType 30 | /** 31 | * The Meps Language Id of this publication. 32 | * 33 | * @default 0 (English) 34 | */ 35 | languageId?: number 36 | } 37 | -------------------------------------------------------------------------------- /packages/express/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../.eslintrc.js') 2 | 3 | /** 4 | * @type { import('eslint').Linter.Config } 5 | */ 6 | module.exports = { 7 | ...baseConfig 8 | } 9 | -------------------------------------------------------------------------------- /packages/express/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [0.11.0](https://github.com/BenShelton/library-api/compare/v0.10.1...v0.11.0) (2021-07-26) 7 | 8 | 9 | ### Features 10 | 11 | * **express:** add endpoint for related publications ([fae1815](https://github.com/BenShelton/library-api/commit/fae18159a50f97f12dc12766820fe2e25ae86867)) 12 | * **express:** add endpoint for retrieving related media ([a790166](https://github.com/BenShelton/library-api/commit/a7901667d312eb0defd9f34b0bf0af1d8b8a3565)) 13 | 14 | 15 | 16 | 17 | 18 | # [0.10.0](https://github.com/BenShelton/library-api/compare/v0.9.1...v0.10.0) (2021-06-23) 19 | 20 | 21 | ### Features 22 | 23 | * **express:** use new media catalog when getting media details ([2d21c24](https://github.com/BenShelton/library-api/commit/2d21c240c90085191cbfc9281213894b34009e2c)), closes [#55](https://github.com/BenShelton/library-api/issues/55) 24 | 25 | 26 | 27 | 28 | 29 | # [0.9.0](https://github.com/BenShelton/library-api/compare/v0.8.0...v0.9.0) (2021-06-10) 30 | 31 | 32 | ### Features 33 | 34 | * **express:** add optional language support on existing endpoints ([7426ec0](https://github.com/BenShelton/library-api/commit/7426ec05df594400b438d76cce2f139c9c13185d)), closes [#12](https://github.com/BenShelton/library-api/issues/12) 35 | 36 | 37 | 38 | 39 | 40 | # [0.8.0](https://github.com/BenShelton/library-api/compare/v0.7.0...v0.8.0) (2021-06-08) 41 | 42 | **Note:** Version bump only for package @library-api/express 43 | 44 | 45 | 46 | 47 | 48 | # [0.7.0](https://github.com/BenShelton/library-api/compare/v0.6.2...v0.7.0) (2021-06-01) 49 | 50 | **Note:** Version bump only for package @library-api/express 51 | 52 | 53 | 54 | 55 | 56 | # [0.6.0](https://github.com/BenShelton/library-api/compare/v0.5.0...v0.6.0) (2021-05-30) 57 | 58 | **Note:** Version bump only for package @library-api/express 59 | 60 | 61 | 62 | 63 | 64 | # [0.5.0](https://github.com/BenShelton/library-api/compare/v0.4.0...v0.5.0) (2021-05-21) 65 | 66 | **Note:** Version bump only for package @library-api/express 67 | 68 | 69 | 70 | 71 | 72 | # [0.4.0](https://github.com/BenShelton/library-api/compare/v0.3.1...v0.4.0) (2021-05-15) 73 | 74 | **Note:** Version bump only for package @library-api/express 75 | 76 | 77 | 78 | 79 | 80 | ## [0.3.1](https://github.com/BenShelton/library-api/compare/v0.3.0...v0.3.1) (2021-05-12) 81 | 82 | **Note:** Version bump only for package @library-api/express 83 | 84 | 85 | 86 | 87 | 88 | # 0.3.0 (2021-05-11) 89 | 90 | 91 | ### Bug Fixes 92 | 93 | * **express/download:** correct error message for /video ([b634708](https://github.com/BenShelton/library-api/commit/b63470844fdd5e340ec5ab427df1339b9b00780b)) 94 | * **packages/express:** use relative imports as we lack path mapping ([5c45e08](https://github.com/BenShelton/library-api/commit/5c45e0894830cc3f42fd3c2d4170e81d46b9a0f8)) 95 | 96 | 97 | ### Features 98 | 99 | * **core:** add id to images/videos, rename video id to doc ([9ec9e8b](https://github.com/BenShelton/library-api/commit/9ec9e8ba6608a4234aab6183b81e87a7c0b0950d)) 100 | * **core:** add id to mediaDetails, allow passing a full video into getMediaDetails for convenience ([2cb6afb](https://github.com/BenShelton/library-api/commit/2cb6afb4e34b46127ccd53a74d588e27258b5495)) 101 | * **core:** rename downloadVideoStream to getVideoStream, add downloadVideoStream which writes file ([cddd05d](https://github.com/BenShelton/library-api/commit/cddd05df59e6595cc446bdf590ae1643ae09ee99)) 102 | * **express:** add /media/details endpoint ([d20ec3f](https://github.com/BenShelton/library-api/commit/d20ec3fb9ffd5affc894f618014a8a23eb3b973e)) 103 | * add oclm publication class ([eab8b92](https://github.com/BenShelton/library-api/commit/eab8b926d2d0457890ffeaad5821a56dc27dc1cc)) 104 | * add parsing for different types of video, add 'doc' video type ([f53907d](https://github.com/BenShelton/library-api/commit/f53907d01eb7b234bf048696f2f9135e94580306)) 105 | * extract shared functionality into core package ([169ea29](https://github.com/BenShelton/library-api/commit/169ea29eacf0048d2de3e0b8101372531fdc24fe)) 106 | -------------------------------------------------------------------------------- /packages/express/README.md: -------------------------------------------------------------------------------- 1 |

2 | Library Express 3 |

4 | 5 |

6 | An Express API for easily accessing information related to meetings and publications of Jehovah's Witnesses. 7 |

8 | 9 |
10 | 11 | ## Description 12 | 13 | This package is brought to you by [Library API](../../README.md). 14 | 15 | ## Documentation 16 | 17 | View the documentation [here](https://benshelton.github.io/library-api/express/) 18 | 19 | ## Development 20 | 21 | Run the following commands to get started. If you are running from the root directory you can add `express` to run these (for example `yarn express dev` instead of just `yarn dev`): 22 | 23 | ```bash 24 | # Start server with hot reload for development 25 | yarn dev 26 | 27 | # Build (outputs to /dist) 28 | yarn build 29 | 30 | # Lint files 31 | yarn lint 32 | 33 | # Run test suite 34 | yarn test 35 | 36 | # Run Type Checking Service 37 | yarn tsc 38 | ``` 39 | -------------------------------------------------------------------------------- /packages/express/jest.config.ts: -------------------------------------------------------------------------------- 1 | import { Config } from '@jest/types' 2 | import { pathsToModuleNameMapper } from 'ts-jest/utils' 3 | 4 | import baseConfig from '../../jest.config.base' 5 | import { compilerOptions } from './test/tsconfig.json' 6 | 7 | const config: Config.InitialOptions = { 8 | ...baseConfig, 9 | moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '/' }) 10 | } 11 | 12 | export default config 13 | -------------------------------------------------------------------------------- /packages/express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@library-api/express", 3 | "private": true, 4 | "version": "0.11.0", 5 | "description": "An Express API for easily accessing information related to meetings and publications of Jehovah's Witnesses.", 6 | "main": "dist/server.js", 7 | "types": "dist/server.d.ts", 8 | "files": [ 9 | "dist", 10 | "types" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/BenShelton/library-api", 15 | "directory": "packages/express" 16 | }, 17 | "scripts": { 18 | "build": "tsc --build tsconfig.json", 19 | "dev": "tsc-watch --build --incremental --onSuccess \"yarn start\"", 20 | "start": "node dist/server.js", 21 | "lint": "eslint . --ext .js,.ts", 22 | "lint:fix": "yarn lint --fix", 23 | "test": "jest --config=jest.config.ts", 24 | "test:bail": "yarn test --bail", 25 | "test:coverage": "yarn test --coverage", 26 | "test:ci": "yarn lint && yarn tsc && yarn test:bail", 27 | "test:watch": "yarn test --watch-all -t", 28 | "test:staged": "yarn test --bail --findRelatedTests", 29 | "tsc": "tsc --noEmit" 30 | }, 31 | "dependencies": { 32 | "@library-api/core": "^0.11.0", 33 | "express": "^4.17.1" 34 | }, 35 | "devDependencies": { 36 | "@types/express": "^4.17.12" 37 | }, 38 | "author": { 39 | "name": "BenShelton", 40 | "email": "bensheltonjones@gmail.com" 41 | }, 42 | "keywords": [ 43 | "jw", 44 | "media", 45 | "library", 46 | "meetings", 47 | "publications", 48 | "api", 49 | "express" 50 | ], 51 | "license": "MIT" 52 | } 53 | -------------------------------------------------------------------------------- /packages/express/src/constants.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | 3 | export const ROOT_DIR = path.join(__dirname, '..') 4 | export const DOWNLOAD_DIR = path.join(ROOT_DIR, 'downloads') 5 | export const CATALOG_FILE = 'catalog.db' 6 | export const CATALOG_PATH = path.join(DOWNLOAD_DIR, CATALOG_FILE) 7 | -------------------------------------------------------------------------------- /packages/express/src/router/catalog.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Router } from 'express' 3 | import { updateCatalog } from '@library-api/core' 4 | 5 | import { CATALOG_PATH } from '../constants' 6 | 7 | import { Catalog } from '../../types/api' 8 | 9 | const router = Router() 10 | 11 | router.post('/update', async (req, res) => { 12 | const updated = await updateCatalog(CATALOG_PATH) 13 | const message = updated ? 'Updated' : 'Already Up To Date' 14 | res.json({ message } as Catalog.Update.Response) 15 | }) 16 | 17 | export const catalog = router 18 | -------------------------------------------------------------------------------- /packages/express/src/router/download.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express' 2 | import { join } from 'path' 3 | import { createReadStream } from 'fs' 4 | import { checkExists, getVideoStream } from '@library-api/core' 5 | 6 | import { DOWNLOAD_DIR } from '../constants' 7 | 8 | import { Download } from '../../types/api' 9 | 10 | const router = Router() 11 | 12 | router.get('/image', (req, res) => { 13 | const { publication, file } = req.query as Partial 14 | if (!publication || !file) return res.status(401).json({ message: 'Publication and File are required' }) 15 | const imagePath = join(DOWNLOAD_DIR, publication, 'contents', file) 16 | if (!checkExists(imagePath)) return res.status(404).json({ message: 'No Image Found' }) 17 | return createReadStream(imagePath).pipe(res) 18 | }) 19 | 20 | router.get('/video', async (req, res) => { 21 | const { type, doc, track, issue, languageId } = req.query as Partial 22 | if (!type || !doc || !track || !issue) return res.status(401).json({ message: 'Type, Doc, Track and Issue are required' }) 23 | const language = Number(languageId || 0) 24 | if (isNaN(language)) { 25 | return res.status(401).json({ message: 'LanguageId must be a number' }) 26 | } 27 | const stream = await getVideoStream({ type, doc, track, issue, languageId: language }) 28 | if (!stream) return res.status(404).json({ message: 'No Video Found' }) 29 | return stream.pipe(res) 30 | }) 31 | 32 | export const download = router 33 | -------------------------------------------------------------------------------- /packages/express/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express' 2 | import { CatalogDatabase } from '@library-api/core' 3 | 4 | import { catalog } from './catalog' 5 | import { download } from './download' 6 | import { media } from './media' 7 | import { publication } from './publication' 8 | import { CATALOG_PATH } from '../constants' 9 | 10 | const router = Router() 11 | 12 | router.get('/monthly-publications', async (req, res) => { 13 | const db = new CatalogDatabase(CATALOG_PATH) 14 | const results = db.getMonthlyPublications() 15 | res.json(results) 16 | }) 17 | 18 | router.use('/catalog', catalog) 19 | router.use('/download', download) 20 | router.use('/media', media) 21 | router.use('/publication', publication) 22 | 23 | // handle 404 24 | router.use((req, res) => { 25 | res.status(404).json({ message: 'Not found' }) 26 | }) 27 | 28 | export { router } 29 | -------------------------------------------------------------------------------- /packages/express/src/router/media.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express' 2 | import { isValidDate, CatalogDatabase, getMediaCatalog } from '@library-api/core' 3 | import { ImageDTO, VideoDTO } from '@library-api/core/types/dto' 4 | 5 | import { CATALOG_PATH, DOWNLOAD_DIR } from '../constants' 6 | 7 | import { Media, ImageDTOWithURL, VideoDTOWithURL } from '../../types/api' 8 | 9 | const router = Router() 10 | 11 | function addImageURL (image: ImageDTO): ImageDTOWithURL { 12 | return { 13 | ...image, 14 | url: `/download/image?publication=${image.filename}&file=${image.filePath}` 15 | } 16 | } 17 | 18 | function addVideoURL (video: VideoDTO): VideoDTOWithURL { 19 | const urlSearchParams = new URLSearchParams({ 20 | type: video.type, 21 | doc: String(video.doc), 22 | track: String(video.track), 23 | issue: String(video.issue) 24 | }) 25 | return { 26 | ...video, 27 | url: '/download/video?' + urlSearchParams.toString() 28 | } 29 | } 30 | 31 | router.get('/watchtower', async (req, res) => { 32 | const { date, languageId } = req.query as Partial 33 | if (!isValidDate(date)) return res.status(401).json({ message: 'Invalid Date' }) 34 | 35 | const language = Number(languageId || 0) 36 | if (isNaN(language)) { 37 | return res.status(401).json({ message: 'LanguageId must be a number' }) 38 | } 39 | 40 | const db = new CatalogDatabase(CATALOG_PATH) 41 | const publication = await db.getPublication(date, DOWNLOAD_DIR, 'wt', language) 42 | if (!publication) return res.status(404).json({ message: 'No Watchtower Found' }) 43 | 44 | const images = (await publication.getImages(date)) 45 | .map(image => addImageURL(image)) 46 | const videos = (await publication.getVideos(date)) 47 | .map(video => addVideoURL(video)) 48 | 49 | const response: Media.Watchtower.Response = { 50 | message: { 51 | images, 52 | videos 53 | } 54 | } 55 | 56 | return res.json(response) 57 | }) 58 | 59 | router.get('/oclm', async (req, res) => { 60 | const { date, languageId } = req.query as Partial 61 | if (!isValidDate(date)) return res.status(401).json({ message: 'Invalid Date' }) 62 | 63 | const language = Number(languageId || 0) 64 | if (isNaN(language)) { 65 | return res.status(401).json({ message: 'LanguageId must be a number' }) 66 | } 67 | 68 | const db = new CatalogDatabase(CATALOG_PATH) 69 | const publication = await db.getPublication(date, DOWNLOAD_DIR, 'oclm', language) 70 | if (!publication) return res.status(404).json({ message: 'No OCLM Workbook Found' }) 71 | 72 | const images = (await publication.getImages(date)) 73 | .map(image => addImageURL(image)) 74 | const videos = (await publication.getVideos(date)) 75 | .map(video => addVideoURL(video)) 76 | 77 | const response: Media.OCLM.Response = { 78 | message: { 79 | images, 80 | videos 81 | } 82 | } 83 | 84 | return res.json(response) 85 | }) 86 | 87 | router.get('/details', async (req, res) => { 88 | const { type, doc, issue, track, languageId } = req.query as Partial 89 | if (type !== 'doc' && type !== 'pub') { 90 | return res.status(401).json({ message: 'Type must be one of "doc" or "pub"' }) 91 | } 92 | if (doc === undefined || issue === undefined || track === undefined) { 93 | return res.status(401).json({ message: 'Doc, Issue & Track are required' }) 94 | } 95 | const language = Number(languageId || 0) 96 | if (isNaN(language)) { 97 | return res.status(401).json({ message: 'LanguageId must be a number' }) 98 | } 99 | 100 | const catalog = await getMediaCatalog(DOWNLOAD_DIR, language) 101 | if (!catalog) return res.status(404).json({ message: 'No Media Catalog Found' }) 102 | const details = await catalog.getMediaDetails({ doc, issue, track }) 103 | if (!details) return res.status(404).json({ message: 'No Media Details Found' }) 104 | 105 | const response: Media.Details.Response = { 106 | message: { 107 | details 108 | } 109 | } 110 | 111 | return res.json(response) 112 | }) 113 | 114 | export const media = router 115 | -------------------------------------------------------------------------------- /packages/express/src/router/publication.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express' 2 | import { isValidDate, CatalogDatabase } from '@library-api/core' 3 | import { ImageDTO, VideoDTO } from '@library-api/core/types/dto' 4 | 5 | import { CATALOG_PATH, DOWNLOAD_DIR } from '../constants' 6 | 7 | import { Publication } from '../../types/api' 8 | 9 | const router = Router() 10 | 11 | router.get('/:type/related-publications', async (req, res) => { 12 | const { type } = req.params 13 | if (type !== 'wt' && type !== 'oclm') return res.status(401).json({ message: 'Route should be /wt/related-publications or /oclm/related-publications' }) 14 | const { date, languageId } = req.query as Partial 15 | if (!isValidDate(date)) return res.status(401).json({ message: 'Invalid Date' }) 16 | 17 | const language = Number(languageId || 0) 18 | if (isNaN(language)) { 19 | return res.status(401).json({ message: 'LanguageId must be a number' }) 20 | } 21 | 22 | const db = new CatalogDatabase(CATALOG_PATH) 23 | const publication = await db.getPublication(date, DOWNLOAD_DIR, type, language) 24 | if (!publication) return res.status(404).json({ message: 'No Publication Found' }) 25 | 26 | const publications = await publication.getRelatedPublications(date) 27 | 28 | const response: Publication.RelatedPublications.Response = { 29 | message: { 30 | publications 31 | } 32 | } 33 | 34 | return res.json(response) 35 | }) 36 | 37 | router.get('/:type/related-media', async (req, res) => { 38 | const { type } = req.params 39 | if (type !== 'wt' && type !== 'oclm') return res.status(401).json({ message: 'Route should be /wt/related-media or /oclm/related-media' }) 40 | const { date, languageId } = req.query as Partial 41 | if (!isValidDate(date)) return res.status(401).json({ message: 'Invalid Date' }) 42 | 43 | const language = Number(languageId || 0) 44 | if (isNaN(language)) { 45 | return res.status(401).json({ message: 'LanguageId must be a number' }) 46 | } 47 | 48 | const db = new CatalogDatabase(CATALOG_PATH) 49 | const publication = await db.getPublication(date, DOWNLOAD_DIR, type, language) 50 | if (!publication) return res.status(404).json({ message: 'No Publication Found' }) 51 | 52 | const publications = await publication.getRelatedPublications(date) 53 | 54 | const images: ImageDTO[] = [] 55 | const videos: VideoDTO[] = [] 56 | 57 | for (const publication of publications) { 58 | const media = await db.getRelatedPublicationMedia(publication, DOWNLOAD_DIR, language) 59 | if (media) { 60 | images.push(...media.images) 61 | videos.push(...media.videos) 62 | } 63 | } 64 | 65 | const response: Publication.RelatedMedia.Response = { 66 | message: { 67 | media: { 68 | images, 69 | videos 70 | } 71 | } 72 | } 73 | 74 | return res.json(response) 75 | }) 76 | 77 | export const publication = router 78 | -------------------------------------------------------------------------------- /packages/express/src/server.ts: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import { createDir, updateCatalog } from '@library-api/core' 3 | 4 | import { router } from './router' 5 | import { CATALOG_PATH, DOWNLOAD_DIR } from './constants' 6 | 7 | const PORT = 3000 8 | 9 | ;(async () => { 10 | // setup system files 11 | await createDir(DOWNLOAD_DIR) 12 | await updateCatalog(CATALOG_PATH) 13 | 14 | const app = express() 15 | app.use(router) 16 | 17 | app.listen(PORT, () => { 18 | console.log(`Listening on port ${PORT}`) 19 | }) 20 | })() 21 | -------------------------------------------------------------------------------- /packages/express/test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: '../.eslintrc.js', 3 | plugins: [ 4 | 'jest' 5 | ], 6 | env: { 7 | 'jest/globals': true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/express/test/server.spec.ts: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import { mocked } from 'ts-jest/utils' 3 | 4 | import '@/server' 5 | import * as core from '@library-api/core' 6 | import { DOWNLOAD_DIR } from '@/constants' 7 | 8 | jest.mock('@library-api/core') 9 | jest.mock('express', () => { 10 | return { 11 | ...jest.requireActual('express'), 12 | __esModule: true, 13 | default: jest.fn().mockReturnValue({ 14 | use: jest.fn(), 15 | listen: jest.fn() 16 | }) 17 | } 18 | }) 19 | 20 | const mockedCore = mocked(core, true) 21 | const mockedExpress = mocked(express, true) 22 | 23 | describe('Server', () => { 24 | test('should setup system files', () => { 25 | expect(mockedCore.createDir).lastCalledWith(DOWNLOAD_DIR) 26 | }) 27 | 28 | test('should start express', () => { 29 | expect(mockedExpress).toBeCalledTimes(1) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /packages/express/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "baseUrl": "../", 6 | "rootDir": "../", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "types": [ 13 | "node", 14 | "jest" 15 | ] 16 | }, 17 | "include": [ 18 | ".", 19 | "../src" 20 | ], 21 | "exclude": [] 22 | } 23 | -------------------------------------------------------------------------------- /packages/express/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "tsBuildInfoFile": "dist/.tsbuildinfo" 8 | }, 9 | "include": [ 10 | "src" 11 | ], 12 | "exclude": [ 13 | "**/*.spec.ts" 14 | ], 15 | "references": [ 16 | { 17 | "path": "../core/tsconfig.json" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/express/types/api.d.ts: -------------------------------------------------------------------------------- 1 | import { ImageDTO, MediaDetailsDTO, RelatedPublicationDTO, VideoDTO } from '@library-api/core/types/dto' 2 | import { PublicationType } from '@library-api/core/types/publication' 3 | 4 | export interface ImageDTOWithURL extends ImageDTO { 5 | url: string 6 | } 7 | 8 | export interface VideoDTOWithURL extends VideoDTO { 9 | url: string 10 | } 11 | 12 | export namespace Catalog { 13 | export namespace Update { 14 | export interface Response { 15 | message: 'Updated' | 'Already Up To Date' 16 | } 17 | } 18 | } 19 | 20 | export namespace Download { 21 | export namespace Image { 22 | export interface QueryParams { 23 | publication: string 24 | file: string 25 | } 26 | } 27 | export namespace Video { 28 | export interface QueryParams { 29 | type: VideoDTO['type'] 30 | doc: string 31 | track: string 32 | issue: string 33 | languageId?: string 34 | } 35 | } 36 | } 37 | 38 | export namespace Media { 39 | export namespace Watchtower { 40 | export interface QueryParams { 41 | date: string 42 | languageId?: string 43 | } 44 | export interface Response { 45 | message: { 46 | images: ImageDTOWithURL[] 47 | videos: VideoDTOWithURL[] 48 | } 49 | } 50 | } 51 | export namespace OCLM { 52 | export interface QueryParams { 53 | date: string 54 | languageId?: string 55 | } 56 | export interface Response { 57 | message: { 58 | images: ImageDTOWithURL[] 59 | videos: VideoDTOWithURL[] 60 | } 61 | } 62 | } 63 | export namespace Details { 64 | export interface QueryParams { 65 | type: VideoDTO['type'] 66 | doc: string | number 67 | issue: number 68 | track: number 69 | languageId?: string 70 | } 71 | export interface Response { 72 | message: { 73 | details: MediaDetailsDTO 74 | } 75 | } 76 | } 77 | } 78 | 79 | export namespace Publication { 80 | export namespace RelatedPublications { 81 | export interface Params { 82 | type: PublicationType 83 | } 84 | export interface QueryParams { 85 | date: string 86 | languageId?: string 87 | } 88 | export interface Response { 89 | message: { 90 | publications: RelatedPublicationDTO[] 91 | } 92 | } 93 | } 94 | 95 | export namespace RelatedMedia { 96 | export interface Params { 97 | type: PublicationType 98 | } 99 | export interface QueryParams { 100 | date: string 101 | languageId?: string 102 | } 103 | export interface Response { 104 | message: { 105 | media: { 106 | images: ImageDTO[] 107 | videos: VideoDTO[] 108 | } 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /packages/media/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../.eslintrc.js') 2 | 3 | /** 4 | * @type { import('eslint').Linter.Config } 5 | */ 6 | module.exports = { 7 | ...baseConfig, 8 | rules: { 9 | 'no-console': 'error' 10 | }, 11 | overrides: [ 12 | ...baseConfig.overrides, 13 | { 14 | files: 'scripts/**/*.js', 15 | rules: { 16 | 'no-console': 'off' 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/media/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | A cross-platform desktop application that simplifies showing media for meetings of Jehovah's Witnesses. 7 |

8 | 9 |
10 | 11 | ## Description 12 | 13 | Finally, non-Windows users can now also display media in a more professional way. 14 | 15 | This package is brought to you by [Library API](../../README.md). 16 | 17 | ## Download 18 | 19 | You can download the latest versions from the [latest releases page](https://github.com/BenShelton/library-api/releases/latest). For Mac you want to `.dmg` file (not the one ending `.blockmap`). You can view more detailed installation instructions [here](https://benshelton.github.io/library-api/media/#installation). 20 | 21 | For other systems you can package this yourself using the `package` command (see [Development](#development). 22 | 23 | ## Documentation 24 | 25 | View the documentation [here](https://benshelton.github.io/library-api/media/). 26 | 27 | ## Development 28 | 29 | Run the following commands to get started. If you are running from the root directory you can add `media` to run these (for example `yarn media dev` instead of just `yarn dev`): 30 | 31 | ```bash 32 | # Start server with hot reload for development 33 | yarn dev 34 | 35 | # Build (outputs to /dist) 36 | yarn build 37 | 38 | # Package the app for testing locally 39 | # Note that local versions will raise app-update errors on startup, they can be ignored 40 | yarn package 41 | 42 | # Lint files 43 | yarn lint 44 | 45 | # Run test suite 46 | yarn test 47 | 48 | # Run Type Checking Service 49 | yarn tsc 50 | ``` 51 | -------------------------------------------------------------------------------- /packages/media/app/main/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('../../.eslintrc.js') 2 | 3 | /** 4 | * @type { import('eslint').Linter.Config } 5 | */ 6 | module.exports = { 7 | ...baseConfig 8 | } 9 | -------------------------------------------------------------------------------- /packages/media/app/main/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { app } from 'electron' 2 | import path from 'path' 3 | 4 | export const ROOT_DIR = app.getPath('userData') 5 | export const DOWNLOAD_DIR = path.join(ROOT_DIR, 'downloads') 6 | export const VIDEO_DIR = path.join(DOWNLOAD_DIR, 'videos') 7 | export const CATALOG_FILE = 'catalog.db' 8 | export const CATALOG_PATH = path.join(DOWNLOAD_DIR, CATALOG_FILE) 9 | -------------------------------------------------------------------------------- /packages/media/app/main/src/directories.ts: -------------------------------------------------------------------------------- 1 | import { readdir, unlink } from 'fs/promises' 2 | import { join } from 'path' 3 | import { createDir } from '@library-api/core' 4 | 5 | import { DOWNLOAD_DIR, VIDEO_DIR } from './constants' 6 | 7 | export async function initDirectories (): Promise { 8 | await createDir(DOWNLOAD_DIR) 9 | await createDir(VIDEO_DIR) 10 | // TODO: Remove this when Media Catalogs are updateable 11 | const files = await readdir(DOWNLOAD_DIR) 12 | for (const file of files) { 13 | if (file.endsWith('.ndjson')) { 14 | await unlink(join(DOWNLOAD_DIR, file)) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/media/app/main/src/events.ts: -------------------------------------------------------------------------------- 1 | import { app } from 'electron' 2 | 3 | import { refocusWindows } from './window' 4 | 5 | export function initEvents (): void { 6 | app.on('activate', async () => { 7 | await refocusWindows() 8 | }) 9 | 10 | app.on('second-instance', async () => { 11 | await refocusWindows() 12 | }) 13 | 14 | app.on('window-all-closed', () => { 15 | app.quit() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /packages/media/app/main/src/index.ts: -------------------------------------------------------------------------------- 1 | import { app } from 'electron' 2 | 3 | import { initDirectories } from './directories' 4 | import { initEvents } from './events' 5 | import { initIPC } from './ipc' 6 | import { initLogger } from './logger' 7 | import { initMenu } from './menu' 8 | import { initUpdater } from './updater' 9 | import { createWindows } from './window' 10 | 11 | (async () => { 12 | // only allow a single instance 13 | if (!app.requestSingleInstanceLock()) { 14 | app.quit() 15 | return 16 | } 17 | 18 | // configure app 19 | initLogger() 20 | initMenu() 21 | initEvents() 22 | await initDirectories() 23 | 24 | // setup everything else 25 | await app.whenReady() 26 | initIPC() 27 | initUpdater() 28 | 29 | // start app 30 | await createWindows() 31 | })() 32 | -------------------------------------------------------------------------------- /packages/media/app/main/src/logger.ts: -------------------------------------------------------------------------------- 1 | import electron, { app, shell } from 'electron' 2 | import log from 'electron-log' 3 | 4 | function submitIssue ({ versions, message }: { versions?: { app: string, os: string }, message: string}): void { 5 | const issueVersions = versions || { app: 'unknown', os: 'unknown' } 6 | if (issueVersions.app === 'unknown') { 7 | try { 8 | issueVersions.app = `${app.name} ${app.getVersion()}` 9 | } catch {} 10 | } 11 | const body = '\n' + 12 | '**Packages & versions**\n' + 13 | `Library Media ${issueVersions.app}\n` + 14 | `OS: ${issueVersions.os}\n\n` + 15 | '**Describe the bug**\n' + 16 | `${message}\n` 17 | const url = new URL('https://github.com/BenShelton/library-api/issues/new') 18 | url.searchParams.append('title', '[Bug] Error report for Library Media') 19 | url.searchParams.append('body', body) 20 | shell.openExternal(url.toString()) 21 | } 22 | 23 | export async function showErrorDialog (error: Error, versions?: { app: string, os: string }): Promise { 24 | const result = await electron.dialog.showMessageBox({ 25 | title: 'An error occurred', 26 | message: error.message, 27 | detail: error.stack, 28 | type: 'error', 29 | buttons: ['Ignore', 'Report', 'Exit'] 30 | }) 31 | if (result.response === 1) { 32 | submitIssue({ 33 | versions, 34 | message: 'Error:\n' + 35 | '```\n' + 36 | `${error.stack}\n` + 37 | '```' 38 | }) 39 | return 40 | } 41 | 42 | if (result.response === 2) { 43 | electron.app.quit() 44 | } 45 | } 46 | 47 | export function initLogger (): void { 48 | log.catchErrors({ 49 | showDialog: false, 50 | onError: showErrorDialog 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /packages/media/app/main/src/menu.ts: -------------------------------------------------------------------------------- 1 | import { app, Menu, shell } from 'electron' 2 | import { MenuItemConstructorOptions } from 'electron/main' 3 | 4 | const isMac = process.platform === 'darwin' 5 | 6 | const template: MenuItemConstructorOptions[] = [] 7 | 8 | if (isMac) { 9 | template.push({ 10 | label: app.name, 11 | submenu: [ 12 | { role: 'about' }, 13 | { type: 'separator' }, 14 | { role: 'services' }, 15 | { type: 'separator' }, 16 | { role: 'hide' }, 17 | { type: 'separator' }, 18 | { role: 'quit' } 19 | ] 20 | }) 21 | } 22 | template.push( 23 | { 24 | label: 'File', 25 | submenu: [ 26 | isMac ? { role: 'close' } : { role: 'quit' } 27 | ] 28 | }, 29 | { 30 | label: 'View', 31 | submenu: [ 32 | { role: 'togglefullscreen' } 33 | ] 34 | }, 35 | { 36 | label: 'Window', 37 | submenu: [ 38 | { role: 'minimize' }, 39 | { role: 'zoom' } 40 | ] 41 | }, 42 | { 43 | role: 'help', 44 | submenu: [ 45 | { 46 | label: 'Open Change Log', 47 | click: async () => { 48 | await shell.openExternal('https://github.com/BenShelton/library-api/blob/master/packages/media/CHANGELOG.md') 49 | } 50 | }, 51 | { 52 | label: 'Open Documentation', 53 | click: async () => { 54 | await shell.openExternal('https://benshelton.github.io/library-api/media/') 55 | } 56 | } 57 | ] 58 | } 59 | ) 60 | 61 | export function initMenu (): void { 62 | const menu = Menu.buildFromTemplate(template) 63 | Menu.setApplicationMenu(menu) 64 | } 65 | -------------------------------------------------------------------------------- /packages/media/app/main/src/updater.ts: -------------------------------------------------------------------------------- 1 | import log from 'electron-log' 2 | import { autoUpdater } from 'electron-updater' 3 | 4 | export function initUpdater (): void { 5 | autoUpdater.logger = log 6 | autoUpdater.checkForUpdatesAndNotify() 7 | } 8 | -------------------------------------------------------------------------------- /packages/media/app/main/src/window.ts: -------------------------------------------------------------------------------- 1 | import { BrowserWindow } from 'electron' 2 | import { URL } from 'url' 3 | import { join } from 'path' 4 | import { checkExists } from '@library-api/core' 5 | import AspectRatioBrowserWindow from 'electron-aspect-ratio-browser-window' 6 | 7 | import { store } from 'shared/src/store' 8 | 9 | import { CATALOG_PATH } from './constants' 10 | 11 | let controlWindow: BrowserWindow | null = null 12 | let displayWindow: BrowserWindow | null = null 13 | 14 | const pageUrl = (import.meta.env.VITE_DEV_SERVER_URL as string | undefined) || 15 | new URL('../renderer/dist/index.html', 'file://' + __dirname).toString() 16 | const preload = join(__dirname, '../../preload/dist/index.cjs') 17 | 18 | function checkDevTools (window: BrowserWindow): void { 19 | if (!import.meta.env.DEV) return 20 | window.webContents.openDevTools({ mode: 'right' }) 21 | } 22 | 23 | export async function createControlWindow (): Promise { 24 | const storeKey = 'controlWindow' 25 | const windowSettings = store.get(storeKey) 26 | controlWindow = new BrowserWindow({ 27 | ...windowSettings, 28 | title: 'Control Panel', 29 | show: true, 30 | webPreferences: { 31 | preload 32 | } 33 | }) 34 | 35 | checkDevTools(controlWindow) 36 | controlWindow.on('close', () => { 37 | if (controlWindow) { 38 | const { x, y, width, height } = controlWindow.getBounds() 39 | store.set('controlWindow', { x, y, width, height }) 40 | } 41 | }) 42 | controlWindow.on('closed', () => { 43 | controlWindow = null 44 | displayWindow?.close() 45 | }) 46 | 47 | const catalogExists = await checkExists(CATALOG_PATH) 48 | 49 | await controlWindow.loadURL(pageUrl + '#' + (catalogExists ? 'control-panel' : 'intro')) 50 | return controlWindow 51 | } 52 | 53 | export async function createDisplayWindow (): Promise { 54 | const storeKey = 'displayWindow' 55 | const windowSettings = store.get(storeKey) 56 | displayWindow = new AspectRatioBrowserWindow({ 57 | ...windowSettings, 58 | title: 'Display', 59 | show: true, 60 | // this prevents Zoom from showing this window as an option 61 | // alwaysOnTop: true, 62 | frame: false, 63 | // TODO: Enable this when fixed, see https://github.com/electron/electron/issues/28686 64 | // roundedCorners: false, 65 | webPreferences: { 66 | preload, 67 | // TODO: This is so we can use local video src in the renderer, there should be a better way 68 | webSecurity: false 69 | } 70 | }) 71 | 72 | displayWindow.setAspectRatio(16 / 9) 73 | 74 | // checkDevTools(displayWindow) 75 | displayWindow.on('close', () => { 76 | if (displayWindow) { 77 | const { x, y, width, height } = displayWindow.getBounds() 78 | store.set('displayWindow', { x, y, width, height }) 79 | } 80 | }) 81 | displayWindow.on('closed', () => { 82 | displayWindow = null 83 | }) 84 | 85 | await displayWindow.loadURL(pageUrl + '#display') 86 | return displayWindow 87 | } 88 | 89 | export async function createWindows (): Promise<[BrowserWindow, BrowserWindow]> { 90 | return Promise.all([ 91 | createControlWindow(), 92 | createDisplayWindow() 93 | ]) 94 | } 95 | 96 | async function getWindow (window: BrowserWindow | null, createFn: () => Promise): Promise { 97 | if (window && !window.isDestroyed()) { 98 | return window 99 | } else { 100 | return createFn() 101 | } 102 | } 103 | 104 | export async function getControlWindow (): Promise { 105 | return getWindow(controlWindow, createControlWindow) 106 | } 107 | 108 | export async function getDisplayWindow (): Promise { 109 | return getWindow(displayWindow, createDisplayWindow) 110 | } 111 | 112 | function refocusWindow (window: BrowserWindow): void { 113 | if (window.isMinimized()) window.restore() 114 | window.focus() 115 | } 116 | 117 | export async function refocusControlWindow (): Promise { 118 | const window = await getControlWindow() 119 | refocusWindow(window) 120 | return window 121 | } 122 | 123 | export async function refocusDisplayWindow (): Promise { 124 | const window = await getDisplayWindow() 125 | refocusWindow(window) 126 | return window 127 | } 128 | 129 | export async function refocusWindows (): Promise<[BrowserWindow, BrowserWindow]> { 130 | return Promise.all([ 131 | refocusControlWindow(), 132 | refocusDisplayWindow() 133 | ]) 134 | } 135 | -------------------------------------------------------------------------------- /packages/media/app/main/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "..", 6 | "module": "es2020", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ], 11 | "shared/*": [ 12 | "../shared/*" 13 | ] 14 | }, 15 | }, 16 | "include": [ 17 | "src/**/*.ts", 18 | "../shared/**/*.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/media/app/main/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path' 2 | import { builtinModules } from 'module' 3 | import { defineConfig } from 'vite' 4 | 5 | const PACKAGE_ROOT = __dirname 6 | 7 | export default defineConfig({ 8 | root: PACKAGE_ROOT, 9 | resolve: { 10 | alias: { 11 | '@/': join(PACKAGE_ROOT, 'src') + '/', 12 | shared: join(PACKAGE_ROOT, '..', 'shared'), 13 | '@library-api/core': join(PACKAGE_ROOT, '..', '..', '..', 'core', 'src', 'index.ts') 14 | } 15 | }, 16 | build: { 17 | sourcemap: 'inline', 18 | target: 'node14', 19 | outDir: 'dist', 20 | assetsDir: '.', 21 | minify: process.env.MODE === 'development' ? false : undefined, // undefined must set default value 22 | lib: { 23 | entry: 'src/index.ts', 24 | formats: ['cjs'] 25 | }, 26 | rollupOptions: { 27 | external: [ 28 | 'electron', 29 | ...builtinModules, 30 | // core modules 31 | 'sqlite', 32 | 'sqlite3', 33 | 'node-fetch', 34 | 'unzipper' 35 | ], 36 | output: { 37 | entryFileNames: '[name].cjs' 38 | } 39 | }, 40 | emptyOutDir: true 41 | } 42 | }) 43 | -------------------------------------------------------------------------------- /packages/media/app/preload/src/index.ts: -------------------------------------------------------------------------------- 1 | import { contextBridge, ipcRenderer } from 'electron' 2 | import { functions } from 'electron-log' 3 | import { getLanguages } from '@library-api/core' 4 | 5 | import { store } from 'shared/src/store' 6 | 7 | import { ElectronApi, StoreApi } from 'shared/types/electron-api' 8 | 9 | const electronApiKey: keyof Window = 'electron' 10 | const electronApi: ElectronApi = { 11 | invoke (channel, args) { 12 | return ipcRenderer.invoke(channel, args) 13 | }, 14 | send (channel, args) { 15 | ipcRenderer.send(channel, args) 16 | }, 17 | on (channel, cb) { 18 | ipcRenderer.on(channel, (_event, args) => cb(args)) 19 | } 20 | } 21 | 22 | const storeApiKey: keyof Window = 'store' 23 | const storeApi: StoreApi = { 24 | get (key: string, defaultValue?: unknown) { 25 | return store.get(key, defaultValue) 26 | }, 27 | set (key, value) { 28 | store.set(key, value) 29 | }, 30 | watch (key, cb) { 31 | return store.onDidChange(key, cb) 32 | } 33 | } 34 | 35 | const logApiKey: keyof Window = 'log' 36 | 37 | const languagesApiKey: keyof Window = 'languages' 38 | const languages = getLanguages() 39 | 40 | contextBridge.exposeInMainWorld(electronApiKey, electronApi) 41 | contextBridge.exposeInMainWorld(storeApiKey, storeApi) 42 | contextBridge.exposeInMainWorld(logApiKey, functions) 43 | contextBridge.exposeInMainWorld(languagesApiKey, languages) 44 | -------------------------------------------------------------------------------- /packages/media/app/preload/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "..", 6 | "module": "es2020", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ], 11 | "shared/*": [ 12 | "../shared/*" 13 | ] 14 | }, 15 | "lib": [ 16 | "esnext", 17 | "dom", 18 | "dom.iterable" 19 | ] 20 | }, 21 | "include": [ 22 | "src/**/*.ts", 23 | "../shared/**/*.ts" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /packages/media/app/preload/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path' 2 | import { builtinModules } from 'module' 3 | import { defineConfig } from 'vite' 4 | 5 | const PACKAGE_ROOT = __dirname 6 | 7 | export default defineConfig({ 8 | root: PACKAGE_ROOT, 9 | resolve: { 10 | alias: { 11 | '@/': join(PACKAGE_ROOT, 'src') + '/', 12 | shared: join(PACKAGE_ROOT, '..', 'shared'), 13 | '@library-api/core': join(PACKAGE_ROOT, '..', '..', '..', 'core', 'src', 'index.ts') 14 | } 15 | }, 16 | build: { 17 | sourcemap: 'inline', 18 | target: 'chrome89', 19 | outDir: 'dist', 20 | assetsDir: '.', 21 | minify: process.env.MODE === 'development' ? false : undefined, // undefined must set default value 22 | lib: { 23 | entry: 'src/index.ts', 24 | formats: ['cjs'] 25 | }, 26 | rollupOptions: { 27 | external: [ 28 | 'electron', 29 | ...builtinModules, 30 | // core modules 31 | 'sqlite', 32 | 'sqlite3', 33 | 'node-fetch', 34 | 'unzipper' 35 | ], 36 | output: { 37 | entryFileNames: '[name].cjs' 38 | } 39 | }, 40 | emptyOutDir: true 41 | } 42 | }) 43 | -------------------------------------------------------------------------------- /packages/media/app/renderer/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | const baseConfig = require('../../.eslintrc.js') 3 | 4 | /** 5 | * @type { import('eslint').Linter.Config } 6 | */ 7 | module.exports = { 8 | ...baseConfig, 9 | extends: [ 10 | ...baseConfig.extends, 11 | 'plugin:vue/vue3-recommended' 12 | ], 13 | env: { 14 | browser: true, 15 | node: false 16 | }, 17 | ignorePatterns: [ 18 | ...baseConfig.ignorePatterns, 19 | 'index.html' 20 | ], 21 | overrides: [ 22 | ...baseConfig.overrides, 23 | { 24 | files: ['src/composables/**/*.ts'], 25 | rules: { 26 | '@typescript-eslint/explicit-module-boundary-types': 'off' 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /packages/media/app/renderer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 126 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/Quicksand.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenShelton/library-api/bafb9731bc1166069f3bc6dff4796f31fd5907ed/packages/media/app/renderer/src/assets/Quicksand.ttf -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/logo-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenShelton/library-api/bafb9731bc1166069f3bc6dff4796f31fd5907ed/packages/media/app/renderer/src/assets/logo-banner.png -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/logo-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenShelton/library-api/bafb9731bc1166069f3bc6dff4796f31fd5907ed/packages/media/app/renderer/src/assets/logo-line.png -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/media.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/picker.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/assets/song.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/components/Controls.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 36 | 37 | 51 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 42 | 43 | 61 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/components/NavbarBtn.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 32 | 33 | 48 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/components/PreviewMedia.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 90 | 91 | 153 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/composables/store.ts: -------------------------------------------------------------------------------- 1 | import { onBeforeUnmount, reactive, toRaw, watch } from 'vue' 2 | 3 | import { StoreDefinition } from 'shared/types/store' 4 | 5 | export function useStore (key: Key) { 6 | const store = reactive(window.store.get(key)) 7 | 8 | watch(store, (newValue) => { 9 | window.store.set(key, toRaw(newValue) as StoreDefinition[Key]) 10 | }) 11 | const unwatch = window.store.watch(key, (newValue) => { 12 | Object.assign(store, newValue) 13 | }) 14 | onBeforeUnmount(() => { 15 | unwatch() 16 | }) 17 | 18 | return { 19 | store 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | 3 | import App from '@/App.vue' 4 | import router from '@/router' 5 | 6 | createApp(App) 7 | .use(router) 8 | .mount('#app') 9 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/pages/ControlPanel/Index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 38 | 39 | 49 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/pages/ControlPanel/Picker.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 36 | 37 | 45 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/pages/ControlPanel/Settings.vue: -------------------------------------------------------------------------------- 1 | 57 | 58 | 100 | 101 | 129 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/pages/ControlPanel/Song.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 103 | 104 | 113 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/pages/Display.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 76 | 77 | 103 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/pages/Intro.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 65 | 66 | 99 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' 2 | 3 | import Intro from '@/pages/Intro.vue' 4 | import ControlPanel from '@/pages/ControlPanel/Index.vue' 5 | import Media from '@/pages/ControlPanel/Media.vue' 6 | import Song from '@/pages/ControlPanel/Song.vue' 7 | import Picker from '@/pages/ControlPanel/Picker.vue' 8 | import Settings from '@/pages/ControlPanel/Settings.vue' 9 | import Display from '@/pages/Display.vue' 10 | 11 | const routes: RouteRecordRaw[] = [ 12 | { 13 | path: '/intro', 14 | name: 'Intro', 15 | component: Intro 16 | }, 17 | { 18 | path: '/control-panel', 19 | name: 'ControlPanel', 20 | component: ControlPanel, 21 | children: [ 22 | { 23 | path: '', 24 | redirect: { name: 'Media' } 25 | }, 26 | { 27 | path: 'media', 28 | name: 'Media', 29 | component: Media 30 | }, 31 | { 32 | path: 'song', 33 | name: 'Song', 34 | component: Song 35 | }, 36 | { 37 | path: 'picker', 38 | name: 'Picker', 39 | component: Picker 40 | }, 41 | { 42 | path: 'settings', 43 | name: 'Settings', 44 | component: Settings 45 | } 46 | ] 47 | }, 48 | { 49 | path: '/display', 50 | name: 'Display', 51 | component: Display 52 | } 53 | ] 54 | 55 | export default createRouter({ 56 | routes, 57 | history: createWebHashHistory() 58 | }) 59 | -------------------------------------------------------------------------------- /packages/media/app/renderer/src/utils/date.ts: -------------------------------------------------------------------------------- 1 | import { SelectOption } from 'types/select' 2 | 3 | /** 4 | * Returns the most recent previous Monday 5 | */ 6 | export function closestPreviousMonday (date: Date): Date { 7 | date.setHours(12) 8 | const day = date.getDay() 9 | date.setDate(date.getDate() - (day === 0 ? 6 : day - 1)) 10 | return date 11 | } 12 | 13 | /** 14 | * Returns true if the passed in date is a Saturday or Sunday 15 | */ 16 | export function isWeekend (date: Date): boolean { 17 | const day = date.getDay() 18 | return day === 0 || day === 6 19 | } 20 | 21 | /** 22 | * Returns an array of select options for every week of the year, starting on Monday 23 | * 24 | * @param year number | string 25 | */ 26 | export function getMondaysOfYear (year: number | string): SelectOption[] { 27 | const d = new Date(year + '-01-01') 28 | const mondays: SelectOption[] = [] 29 | // get the first Monday in the year 30 | while (d.getDay() !== 1) { 31 | d.setDate(d.getDate() + 1) 32 | } 33 | // avoid timezone offsets 34 | d.setHours(12) 35 | // get all the other Mondays in the year 36 | while (d.getFullYear() === year) { 37 | const sunday = new Date(d) 38 | sunday.setDate(d.getDate() + 6) 39 | const options = { month: 'short', day: 'numeric' } as const 40 | const text = `${d.toLocaleDateString(undefined, options)} - ${sunday.toLocaleDateString(undefined, options)}` 41 | mondays.push({ value: formatISODate(d), text }) 42 | d.setDate(d.getDate() + 7) 43 | } 44 | return mondays 45 | } 46 | 47 | /** 48 | * Returns a `yyyy-mm-dd` string from a date 49 | * 50 | * @param date Date 51 | */ 52 | export function formatISODate (date: Date): string { 53 | return date.toISOString().slice(0, 10) 54 | } 55 | -------------------------------------------------------------------------------- /packages/media/app/renderer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "..", 6 | "composite": false, 7 | "module": "es2020", 8 | "paths": { 9 | "@/*": [ 10 | "src/*" 11 | ], 12 | "shared/*": [ 13 | "../shared/*" 14 | ] 15 | }, 16 | "lib": [ 17 | "esnext", 18 | "dom", 19 | "dom.iterable" 20 | ] 21 | }, 22 | "include": [ 23 | "src/**/*.vue", 24 | "src/**/*.ts", 25 | "types/**/*.d.ts", 26 | "../shared/**/*.ts" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /packages/media/app/renderer/types/select.d.ts: -------------------------------------------------------------------------------- 1 | export interface SelectOption { 2 | value: T 3 | text: string 4 | } 5 | -------------------------------------------------------------------------------- /packages/media/app/renderer/types/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { defineComponent } from 'vue' 3 | const component: ReturnType 4 | export default component 5 | } 6 | -------------------------------------------------------------------------------- /packages/media/app/renderer/vite.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | import { join } from 'path' 4 | import { defineConfig } from 'vite' 5 | import vue from '@vitejs/plugin-vue' 6 | 7 | const PACKAGE_ROOT = __dirname 8 | 9 | export default defineConfig({ 10 | root: PACKAGE_ROOT, 11 | resolve: { 12 | alias: { 13 | '@/': join(PACKAGE_ROOT, 'src') + '/', 14 | shared: join(PACKAGE_ROOT, '..', 'shared') 15 | } 16 | }, 17 | plugins: [ 18 | vue({ 19 | template: { 20 | transformAssetUrls: { 21 | img: ['src'], 22 | NavbarBtn: ['src'] 23 | } 24 | } 25 | }) 26 | ], 27 | base: '', 28 | build: { 29 | sourcemap: true, 30 | target: 'chrome89', 31 | polyfillDynamicImport: false, 32 | outDir: 'dist', 33 | assetsDir: '.' 34 | } 35 | }) 36 | -------------------------------------------------------------------------------- /packages/media/app/shared/src/extensions.ts: -------------------------------------------------------------------------------- 1 | export const imageExtensions = [ 2 | 'jpg', 'jpeg', 3 | 'gif', 4 | 'png', 5 | 'bmp', 6 | 'svg', 7 | 'webp', 8 | 'ico' 9 | ] 10 | 11 | export const videoExtensions = [ 12 | 'mp4', 'm4p', 'm4v', 13 | 'ogg', 14 | 'mov', 15 | 'webm' 16 | ] 17 | -------------------------------------------------------------------------------- /packages/media/app/shared/src/store.ts: -------------------------------------------------------------------------------- 1 | import Store from 'electron-store' 2 | 3 | import { StoreDefinition } from '../types/store' 4 | 5 | const devToolsWidth = import.meta.env.DEV ? 350 : 0 6 | 7 | export const store = new Store({ 8 | defaults: { 9 | controlWindow: { 10 | x: 20, 11 | y: 20, 12 | width: 450 + devToolsWidth, 13 | height: 600 14 | }, 15 | displayWindow: { 16 | x: 500 + devToolsWidth, 17 | y: 20, 18 | width: 800, 19 | height: 450 20 | }, 21 | controlPanel: { 22 | showImages: 'display', 23 | languageId: 0 24 | } 25 | }, 26 | migrations: { 27 | '0.7.0': store => { 28 | store.set('controlPanel', { showImages: 'display' }) 29 | }, 30 | '0.8.0': store => { 31 | store.set('controlPanel.languageId', 0) 32 | } 33 | } 34 | }) 35 | -------------------------------------------------------------------------------- /packages/media/app/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": ".", 6 | "module": "es2020" 7 | }, 8 | "include": [ 9 | "src/**/*.ts", 10 | "types/**/*.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/media/app/shared/types/electron-api.d.ts: -------------------------------------------------------------------------------- 1 | import { StoreDefinition } from './store' 2 | 3 | export interface ElectronApi { 4 | invoke (channel: string, args?: T['Args']): Promise 5 | send (channel: string, args?: T['Args']): void 6 | on (channel: string, cb: (args: T['Args']) => void): void 7 | } 8 | 9 | export interface StoreApi { 10 | get (key: Key, defaultValue?: StoreDefinition[Key]): StoreDefinition[Key] 11 | get (key: Key, defaultValue?: Value): Value 12 | set (key: Key, value: StoreDefinition[Key]): void 13 | watch (key: Key, cb: (newValue?: StoreDefinition[Key]) => void): () => void 14 | } 15 | -------------------------------------------------------------------------------- /packages/media/app/shared/types/ipc.d.ts: -------------------------------------------------------------------------------- 1 | import { ImageDTO, MediaDetailsDTO, VideoDTO } from '@library-api/core/types/dto' 2 | 3 | interface MediaDisplayProps { 4 | id: string 5 | src: string 6 | text: string 7 | downloaded: boolean 8 | } 9 | 10 | export type VideoDetails = MediaDisplayProps & { details: MediaDetailsDTO } 11 | 12 | export type IPCImageDTO = ImageDTO & MediaDisplayProps 13 | 14 | export type IPCVideoDTO = VideoDTO & VideoDetails 15 | 16 | interface Invoke { 17 | Args?: unknown 18 | Response: unknown 19 | } 20 | 21 | interface Send { 22 | Args?: unknown 23 | } 24 | 25 | export interface CatalogUpdate extends Invoke { 26 | Response: boolean 27 | } 28 | 29 | export interface PublicationMedia extends Invoke { 30 | Args: { 31 | date: string 32 | type: 'wt' | 'oclm' 33 | languageId: number 34 | } 35 | Response: { videos: IPCVideoDTO[], images: IPCImageDTO[] } | null 36 | } 37 | 38 | export interface DownloadVideo extends Invoke { 39 | Args: { 40 | type: VideoDTO['type'] 41 | doc: string | number 42 | track: number 43 | issue: number 44 | languageId: number 45 | details: MediaDetailsDTO 46 | } 47 | Response: void 48 | } 49 | 50 | export interface DownloadSong extends Invoke { 51 | Args: { 52 | details: MediaDetailsDTO 53 | track: number 54 | languageId: number 55 | } 56 | Response: void 57 | } 58 | 59 | export interface SongDetails extends Invoke { 60 | Args: { 61 | track: number 62 | languageId: number 63 | } 64 | Response: VideoDetails 65 | } 66 | 67 | export interface SettingsClearDownloads extends Invoke { 68 | Args: void 69 | Response: void 70 | } 71 | 72 | export interface MediaPick extends Invoke { 73 | Args?: never 74 | Response: boolean 75 | } 76 | 77 | export interface MediaImage extends Send { 78 | Args: { 79 | src: string 80 | } 81 | } 82 | 83 | export interface MediaVideo extends Send { 84 | Args: { 85 | details: MediaDetailsDTO 86 | } 87 | } 88 | 89 | export interface MediaClear extends Send { 90 | Args?: never 91 | } 92 | 93 | export interface DisplayMedia extends Send { 94 | Args: { 95 | src: string 96 | } 97 | } 98 | 99 | export interface DisplayClear extends Send { 100 | Args?: never 101 | } 102 | -------------------------------------------------------------------------------- /packages/media/app/shared/types/store.d.ts: -------------------------------------------------------------------------------- 1 | interface WindowPosition { 2 | x: number 3 | y: number 4 | width: number 5 | height: number 6 | } 7 | 8 | export interface StoreDefinition { 9 | controlWindow: WindowPosition 10 | displayWindow: WindowPosition 11 | controlPanel: { 12 | showImages: 'all' | 'display' 13 | languageId: number 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/media/app/shared/types/window.d.ts: -------------------------------------------------------------------------------- 1 | declare interface Window { 2 | electron: Readonly 3 | log: import('electron-log').LogFunctions 4 | store: import('./electron-api').StoreApi 5 | languages: (import('@library-api/core/types/dto').LanguageDTO)[] 6 | } 7 | -------------------------------------------------------------------------------- /packages/media/buildResources/entitlements.mac.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-unsigned-executable-memory 6 | 7 | com.apple.security.cs.disable-library-validation 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/media/buildResources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenShelton/library-api/bafb9731bc1166069f3bc6dff4796f31fd5907ed/packages/media/buildResources/icon.png -------------------------------------------------------------------------------- /packages/media/electron-builder.package.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type { import('electron-builder').Configuration } 3 | */ 4 | const config = { 5 | productName: 'Library Media', 6 | directories: { 7 | output: 'dist', 8 | buildResources: 'buildResources' 9 | }, 10 | files: [ 11 | 'app/**/dist/**' 12 | ], 13 | mac: { 14 | hardenedRuntime: true, 15 | gatekeeperAssess: false, 16 | entitlements: 'buildResources/entitlements.mac.plist', 17 | entitlementsInherit: 'buildResources/entitlements.mac.plist' 18 | } 19 | } 20 | 21 | module.exports = config 22 | -------------------------------------------------------------------------------- /packages/media/electron-builder.release.config.js: -------------------------------------------------------------------------------- 1 | const packageConfig = require('./electron-builder.package.config') 2 | 3 | /** 4 | * @type { import('electron-builder').Configuration } 5 | */ 6 | const config = { 7 | ...packageConfig, 8 | dmg: { 9 | sign: false 10 | }, 11 | forceCodeSigning: true, 12 | afterSign: 'scripts/notarize.js', 13 | electronUpdaterCompatibility: '>= 2.16', 14 | publish: { 15 | provider: 'github', 16 | releaseType: 'release' 17 | } 18 | } 19 | 20 | module.exports = config 21 | -------------------------------------------------------------------------------- /packages/media/jest.config.ts: -------------------------------------------------------------------------------- 1 | import { Config } from '@jest/types' 2 | import { pathsToModuleNameMapper } from 'ts-jest/utils' 3 | 4 | import baseConfig from '../../jest.config.base' 5 | import { compilerOptions } from './test/tsconfig.json' 6 | 7 | const config: Config.InitialOptions = { 8 | ...baseConfig, 9 | moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '/' }) 10 | } 11 | 12 | export default config 13 | -------------------------------------------------------------------------------- /packages/media/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@library-api/media", 3 | "productName": "Library Media", 4 | "private": true, 5 | "version": "0.11.0", 6 | "description": "A cross-platform application that simplifies showing media for meetings of Jehovah's Witnesses.", 7 | "main": "app/main/dist/index.cjs", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/BenShelton/library-api", 11 | "directory": "packages/media" 12 | }, 13 | "scripts": { 14 | "build": "node scripts/build.js", 15 | "dev": "node scripts/watch.js", 16 | "start": "electron dist/index.js", 17 | "package": "yarn build && electron-builder build --dir --config electron-builder.package.config.js", 18 | "release": "electron-builder build -m --config electron-builder.release.config.js", 19 | "lint": "eslint . --ext .js,.ts,.vue", 20 | "lint:fix": "yarn lint --fix", 21 | "test": "jest --config=jest.config.ts", 22 | "test:bail": "yarn test --bail", 23 | "test:ci": "yarn lint && yarn tsc && yarn test:bail", 24 | "test:watch": "yarn test --watch-all -t", 25 | "test:staged": "yarn test --bail --findRelatedTests", 26 | "tsc": "yarn tsc:main && yarn tsc:preload && yarn tsc:renderer", 27 | "tsc:main": "tsc -p app/main/tsconfig.json", 28 | "tsc:preload": "tsc -p app/preload/tsconfig.json", 29 | "tsc:renderer": "vue-tsc --noEmit -p app/renderer/tsconfig.json" 30 | }, 31 | "dependencies": { 32 | "@library-api/core": "^0.11.0", 33 | "electron-aspect-ratio-browser-window": "^1.0.2", 34 | "electron-log": "^4.3.5", 35 | "electron-store": "^8.0.0", 36 | "electron-updater": "^4.3.9", 37 | "vue": "3.0.11", 38 | "vue-router": "^4.0.9" 39 | }, 40 | "devDependencies": { 41 | "@vitejs/plugin-vue": "^1.2.3", 42 | "@vue/compiler-sfc": "3.0.11", 43 | "dotenv": "^10.0.0", 44 | "electron": "^13.1.2", 45 | "electron-builder": "^22.11.7", 46 | "electron-notarize": "^1.0.0", 47 | "eslint-plugin-vue": "^7.11.1", 48 | "vite": "^2.3.8", 49 | "vue-tsc": "0.1.0" 50 | }, 51 | "author": { 52 | "name": "BenShelton", 53 | "email": "bensheltonjones@gmail.com" 54 | }, 55 | "keywords": [ 56 | "jw", 57 | "media", 58 | "library", 59 | "meetings", 60 | "publications", 61 | "api", 62 | "electron", 63 | "cross-platform" 64 | ], 65 | "license": "MIT" 66 | } 67 | -------------------------------------------------------------------------------- /packages/media/scripts/build.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/node 2 | const { build } = require('vite') 3 | const { dirname } = require('path') 4 | 5 | /** @type 'production' | 'development' | 'test' */ 6 | const mode = process.env.MODE = process.env.MODE || 'production' 7 | 8 | const packagesConfigs = [ 9 | 'app/main/vite.config.ts', 10 | 'app/preload/vite.config.ts', 11 | 'app/renderer/vite.config.ts' 12 | ] 13 | 14 | /** 15 | * Run `vite build` for config file 16 | */ 17 | const buildByConfig = (configFile) => build({ configFile, mode }); 18 | (async () => { 19 | try { 20 | const totalTimeLabel = 'Total bundling time' 21 | console.time(totalTimeLabel) 22 | 23 | for (const packageConfigPath of packagesConfigs) { 24 | const consoleGroupName = `${dirname(packageConfigPath)}/` 25 | console.group(consoleGroupName) 26 | 27 | const timeLabel = 'Bundling time' 28 | console.time(timeLabel) 29 | 30 | await buildByConfig(packageConfigPath) 31 | 32 | console.timeEnd(timeLabel) 33 | console.groupEnd() 34 | console.log('\n') // Just for pretty print 35 | } 36 | console.timeEnd(totalTimeLabel) 37 | } catch (e) { 38 | console.error(e) 39 | process.exit(1) 40 | } 41 | })() 42 | -------------------------------------------------------------------------------- /packages/media/scripts/notarize.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | const { notarize } = require('electron-notarize') 3 | 4 | /** 5 | * @param { import('electron-builder').AfterPackContext } context 6 | */ 7 | module.exports = async function notarizing (context) { 8 | const { electronPlatformName, appOutDir } = context 9 | if (electronPlatformName !== 'darwin') { 10 | return 11 | } 12 | 13 | const appName = context.packager.appInfo.productFilename 14 | 15 | return await notarize({ 16 | appBundleId: 'com.benshelton.library-media', 17 | appPath: `${appOutDir}/${appName}.app`, 18 | appleId: process.env.APPLE_ID, 19 | appleIdPassword: process.env.APPLE_ID_PASS 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /packages/media/scripts/watch.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/node 2 | 3 | const { createServer, build, createLogger } = require('vite') 4 | const electronPath = require('electron') 5 | const { spawn } = require('child_process') 6 | 7 | /** @type 'production' | 'development' | 'test' */ 8 | const mode = process.env.MODE = process.env.MODE || 'development' 9 | 10 | /** @type { import('vite').LogLevel } */ 11 | const LOG_LEVEL = 'warn' 12 | 13 | /** @type { import('vite').InlineConfig } */ 14 | const sharedConfig = { 15 | mode, 16 | build: { 17 | watch: {} 18 | }, 19 | logLevel: LOG_LEVEL 20 | } 21 | 22 | /** 23 | * @returns { Promise | import('vite').RollupWatcher> } 24 | */ 25 | const getWatcher = ({ name, configFile, writeBundle }) => { 26 | return build({ 27 | ...sharedConfig, 28 | configFile, 29 | plugins: [{ name, writeBundle }] 30 | }) 31 | } 32 | 33 | /** 34 | * Start or restart App when source files are changed 35 | * @param { import('vite').ViteDevServer } viteDevServer 36 | * @returns { Promise | import('vite').RollupWatcher> } 37 | */ 38 | const setupMainPackageWatcher = (viteDevServer) => { 39 | // Write a value to an environment variable to pass it to the main process. 40 | { 41 | const protocol = `http${viteDevServer.config.server.https ? 's' : ''}:` 42 | const host = viteDevServer.config.server.host || 'localhost' 43 | const port = viteDevServer.config.server.port // Vite searches for and occupies the first free port: 3000, 3001, 3002 and so on 44 | const path = '/' 45 | process.env.VITE_DEV_SERVER_URL = `${protocol}//${host}:${port}${path}` 46 | } 47 | 48 | const logger = createLogger(LOG_LEVEL, { 49 | prefix: '[main]' 50 | }) 51 | 52 | /** @type { ChildProcessWithoutNullStreams | null } */ 53 | let spawnProcess = null 54 | 55 | return getWatcher({ 56 | name: 'reload-app-on-main-package-change', 57 | configFile: 'app/main/vite.config.ts', 58 | writeBundle () { 59 | if (spawnProcess !== null) { 60 | spawnProcess.kill('SIGINT') 61 | spawnProcess = null 62 | } 63 | 64 | spawnProcess = spawn(String(electronPath), ['.']) 65 | 66 | spawnProcess.stdout.on('data', d => d.toString().trim() && logger.warn(d.toString(), { timestamp: true })) 67 | spawnProcess.stderr.on('data', d => d.toString().trim() && logger.error(d.toString(), { timestamp: true })) 68 | } 69 | }) 70 | } 71 | 72 | /** 73 | * Start or restart App when source files are changed 74 | * @param { import('vite').ViteDevServer } viteDevServer 75 | * @returns { Promise | import('vite').RollupWatcher> } 76 | */ 77 | const setupPreloadPackageWatcher = (viteDevServer) => { 78 | return getWatcher({ 79 | name: 'reload-page-on-preload-package-change', 80 | configFile: 'app/preload/vite.config.ts', 81 | writeBundle () { 82 | viteDevServer.ws.send({ 83 | type: 'full-reload' 84 | }) 85 | } 86 | }) 87 | }; 88 | 89 | (async () => { 90 | try { 91 | const viteDevServer = await createServer({ 92 | ...sharedConfig, 93 | configFile: 'app/renderer/vite.config.ts' 94 | }) 95 | 96 | await viteDevServer.listen() 97 | 98 | await setupPreloadPackageWatcher(viteDevServer) 99 | await setupMainPackageWatcher(viteDevServer) 100 | } catch (e) { 101 | console.error(e) 102 | process.exit(1) 103 | } 104 | })() 105 | -------------------------------------------------------------------------------- /packages/media/test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: '../.eslintrc.js', 3 | plugins: [ 4 | 'jest' 5 | ], 6 | env: { 7 | 'jest/globals': true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/media/test/renderer/utils/date.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | closestPreviousMonday, 3 | isWeekend 4 | } from '@renderer/utils/date' 5 | 6 | /** 7 | * '2021-05-17' = Mon 17th May 2021 8 | * '2021-05-18' = Tue 18th May 2021 9 | * '2021-05-19' = Wed 19th May 2021 10 | * '2021-05-20' = Thu 20th May 2021 11 | * '2021-05-21' = Fri 21st May 2021 12 | * '2021-05-22' = Sat 22nd May 2021 13 | * '2021-05-23' = Sun 23rd May 2021 14 | * '2021-05-24' = Mon 24th May 2021 15 | */ 16 | 17 | describe('Renderer/Utils: Date', () => { 18 | describe('closestPreviousMonday', () => { 19 | test('should return the closest previous monday', () => { 20 | expect(closestPreviousMonday(new Date('2021-05-17')).toISOString()).toContain('2021-05-17') 21 | expect(closestPreviousMonday(new Date('2021-05-18')).toISOString()).toContain('2021-05-17') 22 | expect(closestPreviousMonday(new Date('2021-05-19')).toISOString()).toContain('2021-05-17') 23 | expect(closestPreviousMonday(new Date('2021-05-20')).toISOString()).toContain('2021-05-17') 24 | expect(closestPreviousMonday(new Date('2021-05-21')).toISOString()).toContain('2021-05-17') 25 | expect(closestPreviousMonday(new Date('2021-05-22')).toISOString()).toContain('2021-05-17') 26 | expect(closestPreviousMonday(new Date('2021-05-23')).toISOString()).toContain('2021-05-17') 27 | expect(closestPreviousMonday(new Date('2021-05-24')).toISOString()).toContain('2021-05-24') 28 | 29 | expect(closestPreviousMonday(new Date('2021-01-01')).toISOString()).toContain('2020-12-28') 30 | }) 31 | }) 32 | 33 | describe('isWeekend', () => { 34 | test('should return true if a weekend', () => { 35 | expect(isWeekend(new Date('2021-05-17'))).toBe(false) 36 | expect(isWeekend(new Date('2021-05-18'))).toBe(false) 37 | expect(isWeekend(new Date('2021-05-19'))).toBe(false) 38 | expect(isWeekend(new Date('2021-05-20'))).toBe(false) 39 | expect(isWeekend(new Date('2021-05-21'))).toBe(false) 40 | expect(isWeekend(new Date('2021-05-22'))).toBe(true) 41 | expect(isWeekend(new Date('2021-05-23'))).toBe(true) 42 | expect(isWeekend(new Date('2021-05-24'))).toBe(false) 43 | }) 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /packages/media/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "baseUrl": "../", 6 | "rootDir": "../", 7 | "paths": { 8 | "@main/*": [ 9 | "app/main/src/*" 10 | ], 11 | "@preload/*": [ 12 | "app/preload/src/*" 13 | ], 14 | "@renderer/*": [ 15 | "app/renderer/src/*" 16 | ], 17 | "types/*": [ 18 | "app/renderer/types/*" 19 | ] 20 | }, 21 | "types": [ 22 | "node", 23 | "jest" 24 | ] 25 | }, 26 | "include": [ 27 | ".", 28 | "../app" 29 | ], 30 | "exclude": [] 31 | } 32 | -------------------------------------------------------------------------------- /packages/media/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "noEmit": true, 6 | "types": [ 7 | "vite/client", 8 | "node" 9 | ] 10 | }, 11 | "include": [], 12 | "exclude": [], 13 | "references": [ 14 | { 15 | "path": "../core/tsconfig.json" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "allowSyntheticDefaultImports": true, 6 | "target": "es2020", 7 | "noImplicitAny": true, 8 | "moduleResolution": "node", 9 | "importHelpers": true, 10 | "sourceMap": true, 11 | "declaration": true, 12 | "declarationMap": true, 13 | "composite": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "resolveJsonModule": true, 17 | "strict": true, 18 | "types": [ 19 | "node" 20 | ] 21 | }, 22 | "include": [], 23 | "exclude": [] 24 | } 25 | -------------------------------------------------------------------------------- /vetur.config.js: -------------------------------------------------------------------------------- 1 | /** @type { import('vls').VeturConfig } */ 2 | module.exports = { 3 | settings: { 4 | 'vetur.useWorkspaceDependencies': true, 5 | 'vetur.experimental.templateInterpolationService': true, 6 | 'vetur.validation.template': false, 7 | 'vetur.validation.templateProps': true 8 | }, 9 | projects: [ 10 | { 11 | root: './packages/media/app/renderer', 12 | package: '../../package.json', 13 | tsconfig: './tsconfig.json' 14 | } 15 | ] 16 | } 17 | --------------------------------------------------------------------------------