Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create homepage UI for channels in zimui #225

Merged
merged 7 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .github/workflows/Tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
pip install -U pip build
python3 -m build --sdist --wheel

build-zimui:
build-and-test-zimui:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
Expand All @@ -65,11 +65,26 @@ jobs:
working-directory: zimui
run: |
yarn install

- name: Build
working-directory: zimui
run: |
yarn build

- name: Start web server
benoit74 marked this conversation as resolved.
Show resolved Hide resolved
working-directory: zimui
run: |
yarn preview &

- name: Wait for web server to be ready
run: |
npx wait-on http://localhost:5173

- name: Run frontend tests
run: |
cd zimui
$(yarn bin)/cypress run

build-docker:
runs-on: ubuntu-22.04
steps:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update scraper to generate JSON files for `zimui` (#212)
- Remove old UI files and methods: template files (home.html, article.html) and `make_html_files` method in scraper.py
- Remove broken locale folder and files used for translation; translation will be restored with #222
- Create "Videos" and "Playlists" tabs for homepage in new Vue.js UI (#213, #214)

## [2.3.0] - 2024-05-22

Expand Down
54 changes: 54 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,57 @@ To add a new locale (`fr` in this example, use only ISO-639-1):
* Upload to PyPI `twine upload dist/youtube2zim-2.0.0*`.
* Commit your CHANGELOG + version bump changes
* Tag version on git `git tag -a v2.0.0`

## developing the ZIM UI in Vue.JS

Sometimes you need to alter something in the ZIM UI in Vue.JS but for this to work, you need assets which are generated by the scraper (e.g. channel.json, ...).

To simplify this, it is possible to:
- run the scraper (with original code base or your modified one)
- extract assets from generated files and place them in a directory where ZIM UI will find them
- iterate on ZIM UI code

To achieve this, first build the Docker image based on current code base.

```
docker build -t local-youtube2zim .
```

Scrape a channel (here we use the [openZIM_testing](https://www.youtube.com/channel/UC8elThf5TGMpQfQc_VE917Q) channel, but you could use any other one of interest for your UI developments).

```
docker run --rm -it -v "$PWD/output":/output local-youtube2zim youtube2zim --api-key <YOUR-API-KEY> --type channel --id "UC8elThf5TGMpQfQc_VE917Q" --name "openZIM_testing" --zim-file "openZIM_testing"
```

Extract interesting ZIM content and move it to `public` folder.

```
find zimui/public/ -mindepth 1 ! -name ".gitignore" -delete
docker run -it --rm -v $(pwd)/output:/data ghcr.io/openzim/zim-tools:latest zimdump dump --dir=/data/openZIM_testing /data/openZIM_testing.zim
sudo chown -R $(id -u -n):$(id -g -n) output/openZIM_testing
mv output/openZIM_testing/* zimui/public/
rm -rf output/openZIM_testing
```

Start ZIM UI locally.

```
cd zimui
yarn dev
```

Do not forget to cleanup `public` folder before building the docker image again, otherwise all assets will be pushed to the ZIM.
benoit74 marked this conversation as resolved.
Show resolved Hide resolved

## testing with cypress

Cypress is used for end-to-end testing of the ZIM UI. It allows you to write tests that simulate user interactions with the application to ensure everything works as expected.

To run the tests, you need to start the ZIM UI locally and then run the tests.

```
cd zimui
yarn dev
yarn test:e2e
```

On Linux, you might need to install additional dependencies, see [Linux Prerequisites](https://docs.cypress.io/guides/getting-started/installing-cypress#Linux-Prerequisites) in the Cypress documentation.
15 changes: 0 additions & 15 deletions scraper/src/youtube2zim/scraper.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,15 +844,6 @@ def download_authors_branding(self):
)
for channel_id in uniq_channel_ids:
save_channel_branding(self.channels_dir, channel_id, save_banner=False)
self.copy_default_banner(channel_id)

def copy_default_banner(self, channel_id):
banner_path = self.channels_dir / channel_id / "banner.jpg"
if not banner_path.exists():
shutil.copy(
self.templates_dir / "assets" / "banner.jpg",
self.channels_dir / channel_id / "banner.jpg",
)

def update_metadata(self):
# we use title, description, profile and banner of channel/user
Expand All @@ -867,7 +858,6 @@ def update_metadata(self):
save_channel_branding(
self.channels_dir, self.main_channel_id, save_banner=True
)
self.copy_default_banner(self.main_channel_id)

# if a single playlist was requested, use if for names;
# otherwise, use main_channel's details.
Expand Down Expand Up @@ -906,11 +896,6 @@ def update_metadata(self):
self.channels_dir.joinpath(self.main_channel_id, "profile.jpg"),
self.profile_path,
)
if not self.banner_path.exists():
shutil.copy(
self.channels_dir.joinpath(self.main_channel_id, "banner.jpg"),
self.banner_path,
)

# set colors from images if not supplied
if self.main_color is None or self.secondary_color is None:
Expand Down
Binary file removed scraper/src/youtube2zim/templates/assets/banner.jpg
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions zimui/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from 'cypress'

export default defineConfig({
e2e: {
setupNodeEvents() {
// implement node event listeners here
},
baseUrl: 'http://localhost:5173'
}
})
35 changes: 35 additions & 0 deletions zimui/cypress/e2e/channel_home_page.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
describe('home page for a channel', () => {
beforeEach(() => {
cy.intercept('GET', '/channel.json', { fixture: 'channel/channel.json' }).as('getChannel')
cy.intercept('GET', '/playlists/uploads_from_openzim_testing-917Q.json', {
fixture: 'channel/playlists/uploads_from_openzim_testing-917Q.json'
}).as('getUploads')
cy.visit('/')
cy.wait('@getChannel')
cy.wait('@getUploads')
})

it('loads the videos tab', () => {
cy.contains('2 videos').should('be.visible')
cy.contains('Coffee Machine').should('be.visible')
cy.contains('Timelapse').should('be.visible')
})

it('loads the playlist tab', () => {
cy.intercept('GET', '/playlists.json', { fixture: 'channel/playlists.json' }).as('getPlaylists')
cy.contains('.v-btn__content', 'Playlists').click()
cy.url().should('include', '/playlists')
cy.wait('@getPlaylists')

cy.contains('3 playlists').should('be.visible')
cy.contains('Timelapses').should('be.visible')
cy.contains('Trailers').should('be.visible')
cy.contains('Coffee').should('be.visible')
})

it('opens and loads "About Channel" dialog', () => {
cy.contains('.v-btn__content', 'About Channel').click()
cy.contains('Description for openZIM_testing').should('be.visible')
cy.contains('Jun 4, 2024').should('be.visible')
})
})
12 changes: 12 additions & 0 deletions zimui/cypress/fixtures/channel/channel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"id": "UC8elThf5TGMpQfQc_VE917Q",
"title": "openZIM_testing",
"description": "-",
"channelName": "openZIM_testing",
"channelDescription": "Description for openZIM_testing",
"profilePath": "profile.jpg",
"bannerPath": "banner.jpg",
"joinedDate": "2024-06-04T13:30:16.232286Z",
"collectionType": "channel",
"mainPlaylist": "uploads_from_openzim_testing-917Q"
}
28 changes: 28 additions & 0 deletions zimui/cypress/fixtures/channel/playlists.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"playlists": [
{
"slug": "timelapses-QgGI",
"id": "PLMK6hZr9PcsjcF5mnaQk8Fi-xnb0AQgGI",
"title": "Timelapses",
"thumbnailPath": "videos/9TgosbGRsTk/video.webp",
"videosCount": 2,
"mainVideoSlug": "timelapse-9Tgo"
},
{
"slug": "trailers-5Gph",
"id": "PLMK6hZr9PcshJpNSRVaKReGlwhVlh5Gph",
"title": "Trailers",
"thumbnailPath": "videos/TcMBFSGVi1c/video.webp",
"videosCount": 1,
"mainVideoSlug": "marvel_studios_avengers_endgame_official_trailer-TcMB"
},
{
"slug": "coffee-O2wS",
"id": "PLMK6hZr9PcsjTJ5u2z-khzvDNXlqdO2wS",
"title": "Coffee",
"thumbnailPath": "videos/DYvYGQHYScc/video.webp",
"videosCount": 1,
"mainVideoSlug": "coffee_machine-DYvY"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"id": "UU8elThf5TGMpQfQc_VE917Q",
"author": {
"channelId": "UC8elThf5TGMpQfQc_VE917Q",
"channelTitle": "openZIM_testing",
"profilePath": "channels/UC8elThf5TGMpQfQc_VE917Q/profile.jpg",
"bannerPath": "channels/UC8elThf5TGMpQfQc_VE917Q/banner.jpg"
},
"title": "Uploads from openZIM_testing",
"description": "",
"publicationDate": "2024-06-04T14:57:45Z",
"thumbnailPath": "videos/DYvYGQHYScc/video.webp",
"videos": [
{
"slug": "coffee_machine-DYvY",
"id": "DYvYGQHYScc",
"title": "Coffee Machine",
"thumbnailPath": "videos/DYvYGQHYScc/video.webp",
"duration": "PT9S"
},
{
"slug": "timelapse-9Tgo",
"id": "9TgosbGRsTk",
"title": "Timelapse",
"thumbnailPath": "videos/9TgosbGRsTk/video.webp",
"duration": "PT11S"
}
],
"videosCount": 2
}
37 changes: 37 additions & 0 deletions zimui/cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
20 changes: 20 additions & 0 deletions zimui/cypress/support/e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands'

// Alternatively you can use CommonJS syntax:
// require('./commands')
10 changes: 10 additions & 0 deletions zimui/cypress/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"noEmit": true,
// be explicit about types included
// to avoid clashing with Jest types
"types": ["cypress"]
},
"include": ["../node_modules/cypress", "./**/*.ts"]
}
6 changes: 5 additions & 1 deletion zimui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@
"name": "zimui",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"test:unit": "vitest",
"test:e2e": "cypress run",
"build-only": "vite build",
"type-check": "vue-tsc --build --force",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"@fontsource/roboto": "^5.0.13",
"axios": "^1.7.2",
"dayjs": "^1.11.11",
"pinia": "^2.1.7",
"vite-plugin-vuetify": "^2.0.3",
"vue": "^3.4.21",
Expand All @@ -31,6 +34,7 @@
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/test-utils": "^2.4.5",
"@vue/tsconfig": "^0.5.1",
"cypress": "^13.11.0",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"jsdom": "^24.0.0",
Expand Down
1 change: 1 addition & 0 deletions zimui/public/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*
12 changes: 11 additions & 1 deletion zimui/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
<script setup lang="ts">
import { RouterView } from 'vue-router'
import { useMainStore } from '@/stores/main'

import ErrorDisplay from '@/components/common/ErrorDisplay.vue'

const main = useMainStore()
</script>

<template>
<v-app>
<v-main>
<router-view />
<div v-if="main.errorMessage">
<error-display />
</div>
<div v-else>
<router-view />
</div>
</v-main>
</v-app>
</template>
Expand Down
Binary file added zimui/src/assets/images/banner-placeholder.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added zimui/src/assets/images/dead-kiwix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added zimui/src/assets/images/profile-placeholder.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added zimui/src/assets/images/thumbnail-placeholder.webp
Binary file not shown.
Loading
Loading