V4
This commit is contained in:
parent
49a88bcbaf
commit
938a5c7ee8
295
.github/workflows/v4.yml
vendored
Normal file
295
.github/workflows/v4.yml
vendored
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
name: Build v4
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- v4
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- v4
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pre-check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
pyMetadata: ${{ steps.filter.outputs.pyMetadata }}
|
||||||
|
coordinator: ${{ steps.filter.outputs.coordinator }}
|
||||||
|
processer: ${{ steps.filter.outputs.processer }}
|
||||||
|
converter: ${{ steps.filter.outputs.converter }}
|
||||||
|
shared: ${{ steps.filter.outputs.shared }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: dorny/paths-filter@v2
|
||||||
|
id: filter
|
||||||
|
with:
|
||||||
|
filters: |
|
||||||
|
pyMetadata:
|
||||||
|
- 'apps/pyMetadata/**'
|
||||||
|
apps/coordinator:
|
||||||
|
- 'apps/coordinator/**'
|
||||||
|
apps/processer:
|
||||||
|
- 'apps/processer/**'
|
||||||
|
apps/converter:
|
||||||
|
- 'apps/converter/**'
|
||||||
|
|
||||||
|
shared:
|
||||||
|
- 'shared/**'
|
||||||
|
# Step to print the outputs from "pre-check" job
|
||||||
|
- name: Print Outputs from pre-check job
|
||||||
|
run: |
|
||||||
|
echo "Apps\n"
|
||||||
|
echo "app:pyMetadata: ${{ needs.pre-check.outputs.pyMetadata }}"
|
||||||
|
echo "app:coordinator: ${{ needs.pre-check.outputs.coordinator }}"
|
||||||
|
echo "app:processer: ${{ needs.pre-check.outputs.processer }}"
|
||||||
|
echo "app:converter: ${{ needs.pre-check.outputs.converter }}"
|
||||||
|
|
||||||
|
echo "Shared"
|
||||||
|
echo "shared: ${{ needs.pre-check.outputs.shared }}"
|
||||||
|
echo "\n"
|
||||||
|
echo "${{ needs.pre-check.outputs }}"
|
||||||
|
echo "${{ needs.pre-check }}"
|
||||||
|
|
||||||
|
build-shared:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: pre-check
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Cache Shared code Gradle dependencies
|
||||||
|
id: cache-gradle
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.gradle/caches
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('shared/build.gradle.kts') }}
|
||||||
|
|
||||||
|
- name: Build Shared code
|
||||||
|
if: steps.cache-gradle.outputs.cache-hit != 'true' || needs.pre-check.outputs.shared == 'true' || github.event_name == 'workflow_dispatch'
|
||||||
|
run: |
|
||||||
|
chmod +x ./gradlew
|
||||||
|
./gradlew :shared:build --stacktrace --info
|
||||||
|
|
||||||
|
|
||||||
|
build-processer:
|
||||||
|
needs: build-shared
|
||||||
|
if: ${{ needs.pre-check.outputs.processer == 'true' || github.event_name == 'workflow_dispatch' || needs.pre-check.outputs.shared == 'true' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
#if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Cache Shared Gradle dependencies
|
||||||
|
id: cache-gradle
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.gradle/caches
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('shared/build.gradle.kts') }}
|
||||||
|
|
||||||
|
- name: Extract version from build.gradle.kts
|
||||||
|
id: extract_version
|
||||||
|
run: |
|
||||||
|
VERSION=$(cat ./apps/processer/build.gradle.kts | grep '^version\s*=\s*\".*\"' | sed 's/^version\s*=\s*\"\(.*\)\"/\1/')
|
||||||
|
echo "VERSION=$VERSION"
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build Processer module
|
||||||
|
id: build-processer
|
||||||
|
run: |
|
||||||
|
chmod +x ./gradlew
|
||||||
|
./gradlew :apps:processer:bootJar --info --stacktrace
|
||||||
|
echo "Build completed"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Generate Docker image tag
|
||||||
|
id: docker-tag
|
||||||
|
run: echo "::set-output name=tag::$(date -u +'%Y.%m.%d')-$(uuidgen | cut -c 1-8)"
|
||||||
|
|
||||||
|
- name: Docker login
|
||||||
|
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||||
|
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./dockerfiles/DebianJavaFfmpeg
|
||||||
|
build-args: |
|
||||||
|
MODULE_NAME=processer
|
||||||
|
PASS_APP_VERSION=${{ env.VERSION }}
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
bskjon/mediaprocessing-processer:v4
|
||||||
|
bskjon/mediaprocessing-processer:v4-${{ github.sha }}
|
||||||
|
bskjon/mediaprocessing-processer:v4-${{ steps.docker-tag.outputs.tag }}
|
||||||
|
|
||||||
|
build-converter:
|
||||||
|
needs: build-shared
|
||||||
|
if: ${{ needs.pre-check.outputs.converter == 'true' || github.event_name == 'workflow_dispatch' || needs.pre-check.outputs.shared == 'true' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
#if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Cache Shared Gradle dependencies
|
||||||
|
id: cache-gradle
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.gradle/caches
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('shared/build.gradle.kts') }}
|
||||||
|
|
||||||
|
- name: Extract version from build.gradle.kts
|
||||||
|
id: extract_version
|
||||||
|
run: |
|
||||||
|
VERSION=$(cat ./apps/converter/build.gradle.kts | grep '^version\s*=\s*\".*\"' | sed 's/^version\s*=\s*\"\(.*\)\"/\1/')
|
||||||
|
echo "VERSION=$VERSION"
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build Converter module
|
||||||
|
id: build-converter
|
||||||
|
run: |
|
||||||
|
chmod +x ./gradlew
|
||||||
|
./gradlew :apps:converter:bootJar --info --debug
|
||||||
|
echo "Build completed"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Generate Docker image tag
|
||||||
|
id: docker-tag
|
||||||
|
run: echo "::set-output name=tag::$(date -u +'%Y.%m.%d')-$(uuidgen | cut -c 1-8)"
|
||||||
|
|
||||||
|
- name: Docker login
|
||||||
|
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||||
|
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./dockerfiles/DebianJava
|
||||||
|
build-args: |
|
||||||
|
MODULE_NAME=converter
|
||||||
|
PASS_APP_VERSION=${{ env.VERSION }}
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
bskjon/mediaprocessing-converter:v4
|
||||||
|
bskjon/mediaprocessing-converter:v4-${{ github.sha }}
|
||||||
|
bskjon/mediaprocessing-converter:v4-${{ steps.docker-tag.outputs.tag }}
|
||||||
|
|
||||||
|
build-coordinator:
|
||||||
|
needs: build-shared
|
||||||
|
if: ${{ needs.pre-check.outputs.coordinator == 'true' || github.event_name == 'workflow_dispatch' || needs.pre-check.outputs.shared == 'true' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
#if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Cache Shared Gradle dependencies
|
||||||
|
id: cache-gradle
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.gradle/caches
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('shared/build.gradle.kts') }}
|
||||||
|
|
||||||
|
- name: Extract version from build.gradle.kts
|
||||||
|
id: extract_version
|
||||||
|
run: |
|
||||||
|
VERSION=$(cat ./apps/coordinator/build.gradle.kts | grep '^version\s*=\s*\".*\"' | sed 's/^version\s*=\s*\"\(.*\)\"/\1/')
|
||||||
|
echo "VERSION=$VERSION"
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Coordinator module
|
||||||
|
id: build-coordinator
|
||||||
|
run: |
|
||||||
|
chmod +x ./gradlew
|
||||||
|
./gradlew :apps:coordinator:bootJar
|
||||||
|
echo "Build completed"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Generate Docker image tag
|
||||||
|
id: docker-tag
|
||||||
|
run: echo "::set-output name=tag::$(date -u +'%Y.%m.%d')-$(uuidgen | cut -c 1-8)"
|
||||||
|
|
||||||
|
- name: Docker login
|
||||||
|
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||||
|
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Debug Check extracted version
|
||||||
|
run: |
|
||||||
|
echo "Extracted version: ${{ env.VERSION }}"
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./dockerfiles/DebianJavaFfmpeg
|
||||||
|
build-args: |
|
||||||
|
MODULE_NAME=coordinator
|
||||||
|
PASS_APP_VERSION=${{ env.VERSION }}
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
bskjon/mediaprocessing-coordinator:v4
|
||||||
|
bskjon/mediaprocessing-coordinator:v4-${{ github.sha }}
|
||||||
|
bskjon/mediaprocessing-coordinator:v4-${{ steps.docker-tag.outputs.tag }}
|
||||||
|
|
||||||
|
build-pymetadata:
|
||||||
|
needs: pre-check
|
||||||
|
if: ${{ needs.pre-check.outputs.pyMetadata == 'true' || github.event_name == 'workflow_dispatch' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Build pyMetadata module
|
||||||
|
id: build-pymetadata
|
||||||
|
run: |
|
||||||
|
if [[ "${{ steps.check-pymetadata.outputs.changed }}" == "true" || "${{ github.event_name }}" == "push" || "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||||
|
cd apps/pyMetadata
|
||||||
|
# Add the necessary build steps for your Python module here
|
||||||
|
echo "Build completed"
|
||||||
|
else
|
||||||
|
echo "pyMetadata has not changed. Skipping pyMetadata module build."
|
||||||
|
echo "::set-output name=job_skipped::true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Generate Docker image tag
|
||||||
|
id: docker-tag
|
||||||
|
run: echo "::set-output name=tag::$(date -u +'%Y.%m.%d')-$(uuidgen | cut -c 1-8)"
|
||||||
|
|
||||||
|
- name: Docker login
|
||||||
|
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||||
|
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: docker/build-push-action@v5.1.0
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./dockerfiles/Python
|
||||||
|
build-args:
|
||||||
|
MODULE_NAME=pyMetadata
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
bskjon/mediaprocessing-pymetadata:v4
|
||||||
|
bskjon/mediaprocessing-pymetadata:v4-${{ github.sha }}
|
||||||
|
bskjon/mediaprocessing-pymetadata:v4-${{ steps.docker-tag.outputs.tag }}
|
||||||
399
.idea/workspace.xml
generated
399
.idea/workspace.xml
generated
@ -4,37 +4,44 @@
|
|||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="79fc3e25-8083-4c15-b17f-a1e0d61c77a6" name="Changes" comment="">
|
<list default="true" id="79fc3e25-8083-4c15-b17f-a1e0d61c77a6" name="Changes" comment="Closing connection after every query">
|
||||||
<change afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/dto/EventChain.kt" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/store/ContentCatalogStore.kt" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/service/AvailableEventsService.kt" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/store/ContentCompletionMover.kt" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/service/CompletedEventsService.kt" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/store/ContentGenresStore.kt" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/service/EventExecutionOrderService.kt" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/store/ContentMetadataStore.kt" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/socket/ChainedEventsTopic.kt" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/store/ContentSubtitleStore.kt" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/database/EventsDatabase.kt" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/store/ContentTitleStore.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/validator/CompletionValidator.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/CoordinatorApplication.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/CoordinatorApplication.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/converter/src/main/kotlin/no/iktdev/mediaprocessing/converter/tasks/ConvertService.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/converter/src/main/kotlin/no/iktdev/mediaprocessing/converter/tasks/ConvertService.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/EventsManager.kt" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/build.gradle.kts" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/build.gradle.kts" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/CompletedTaskListener.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/CompletedTaskListener.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/Configuration.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/Configuration.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/ConvertWorkTaskListener.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/ConvertWorkTaskListener.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/UIApplication.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/UIApplication.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/CoverDownloadTaskListener.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/CoverDownloadTaskListener.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/UIEnv.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/UIEnv.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/CoverFromMetadataTaskListener.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/CoverFromMetadataTaskListener.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/dto/EventSummary.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/dto/EventSummary.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/EncodeWorkArgumentsTaskListener.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/EncodeWorkArgumentsTaskListener.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/dto/ExplorerAttr.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/dto/explore/ExplorerAttr.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/ExtractWorkArgumentsTaskListener.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/ExtractWorkArgumentsTaskListener.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/dto/ExplorerCursor.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/dto/explore/ExplorerCursor.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/MediaOutInformationTaskListener.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/listeners/MediaOutInformationTaskListener.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/explorer/ExplorerCore.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/explorer/ExplorerCore.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/EncodeWorkArgumentsMapping.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/EncodeWorkArgumentsMapping.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/socket/EventsTableTopic.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/socket/EventsTableTopic.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/ExtractWorkArgumentsMapping.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/ExtractWorkArgumentsMapping.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/socket/ExplorerTopic.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/socket/ExplorerTopic.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/test/kotlin/no/iktdev/mediaprocessing/coordinator/reader/BaseInfoFromFileTest.kt" beforeDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/socket/TopicSupport.kt" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/coordinator/src/test/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/EncodeWorkArgumentsMappingTest.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/coordinator/src/test/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/EncodeWorkArgumentsMappingTest.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/ffmpeg/FfmpegTaskService.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/ffmpeg/FfmpegTaskService.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/services/EncodeService.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/services/EncodeService.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/services/ExtractService.kt" beforeDir="false" afterPath="$PROJECT_DIR$/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/services/ExtractService.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/web/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/web/package-lock.json" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/ui/web/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/web/package-lock.json" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/web/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/web/package.json" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/ui/web/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/web/package.json" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/web/src/App.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/web/src/App.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/apps/ui/web/src/app/page/EventsChainPage.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/web/src/app/page/EventsChainPage.tsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/web/src/app/page/ExplorePage.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/web/src/app/page/ExplorePage.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/SharedConfig.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/SharedConfig.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/apps/ui/web/src/app/page/LaunchPage.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/apps/ui/web/src/app/page/LaunchPage.tsx" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/Utils.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/Utils.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/EventToClazzTable.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/EventToClazzTable.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/ConvertWorkCreatedEvent.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/ConvertWorkCreatedEvent.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/database/cal/EventsManager.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/database/cal/EventsManager.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/ConvertWorkPerformed.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/ConvertWorkPerformed.kt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/shared/eventi/src/main/kotlin/no/iktdev/eventi/implementations/EventCoordinator.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/eventi/src/main/kotlin/no/iktdev/eventi/implementations/EventCoordinator.kt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/EncodeArgumentCreatedEvent.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/EncodeArgumentCreatedEvent.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/ExtractArgumentCreatedEvent.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/ExtractArgumentCreatedEvent.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/ExtractWorkPerformedEvent.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/ExtractWorkPerformedEvent.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/MediaCoverInfoReceivedEvent.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/MediaCoverInfoReceivedEvent.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/MediaOutInformationConstructedEvent.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/data/MediaOutInformationConstructedEvent.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/shared/eventi/src/test/kotlin/no/iktdev/eventi/mock/MockEventManager.kt" beforeDir="false" afterPath="$PROJECT_DIR$/shared/eventi/src/test/kotlin/no/iktdev/eventi/mock/MockEventManager.kt" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@ -43,7 +50,7 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="ChangesViewManager">
|
<component name="ChangesViewManager">
|
||||||
<option name="groupingKeys">
|
<option name="groupingKeys">
|
||||||
<option value="module" />
|
<option value="directory" />
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ExternalProjectsData">
|
<component name="ExternalProjectsData">
|
||||||
@ -87,10 +94,16 @@
|
|||||||
<list>
|
<list>
|
||||||
<option value="JUnit5 Test Class" />
|
<option value="JUnit5 Test Class" />
|
||||||
<option value="Kotlin Class" />
|
<option value="Kotlin Class" />
|
||||||
|
<option value="Kotlin Object" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="Git.Settings">
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||||
|
<map>
|
||||||
|
<entry key="$PROJECT_DIR$" value="v3" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
<component name="MarkdownSettingsMigration">
|
<component name="MarkdownSettingsMigration">
|
||||||
@ -105,28 +118,32 @@
|
|||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">{
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
"Gradle.AudioArgumentsTest.executor": "Run",
|
"Gradle.AudioArgumentsTest.executor": "Run",
|
||||||
"Gradle.AudioArgumentsTest.validateChecks1.executor": "Run",
|
"Gradle.AudioArgumentsTest.validateChecks1.executor": "Run",
|
||||||
"Gradle.AudioArgumentsTest.validateChecks3.executor": "Run",
|
"Gradle.AudioArgumentsTest.validateChecks3.executor": "Run",
|
||||||
"Gradle.Build MediaProcessing2.executor": "Run",
|
"Gradle.Build MediaProcessing2.executor": "Run",
|
||||||
"Gradle.EncodeArgumentCreatorTaskTest.executor": "Run",
|
"Gradle.EncodeArgumentCreatorTaskTest.executor": "Run",
|
||||||
"Gradle.MediaProcessing2 [build].executor": "Run",
|
"Gradle.FileNameParserTest.assertDotRemoval.executor": "Run",
|
||||||
"Kotlin.UIApplicationKt.executor": "Run",
|
"Gradle.FileNameParserTest.assertTitleFails.executor": "Run",
|
||||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
"Gradle.FileNameParserTest.executor": "Run",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"Gradle.MediaProcessing2 [build].executor": "Run",
|
||||||
"com.intellij.testIntegration.createTest.CreateTestDialog.defaultLibrary": "JUnit5",
|
"Kotlin.Env - CoordinatorApplicationKt.executor": "Run",
|
||||||
"com.intellij.testIntegration.createTest.CreateTestDialog.defaultLibrarySuperClass.JUnit5": "",
|
"Kotlin.UIApplicationKt.executor": "Run",
|
||||||
"git-widget-placeholder": "v3",
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||||
"ignore.virus.scanning.warn.message": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"kotlin-language-version-configured": "true",
|
"com.intellij.testIntegration.createTest.CreateTestDialog.defaultLibrary": "JUnit5",
|
||||||
"last_opened_file_path": "D:/Workspace/MediaProcessing2/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract",
|
"com.intellij.testIntegration.createTest.CreateTestDialog.defaultLibrarySuperClass.JUnit5": "",
|
||||||
"project.structure.last.edited": "Modules",
|
"git-widget-placeholder": "v4",
|
||||||
"project.structure.proportion": "0.0",
|
"ignore.virus.scanning.warn.message": "true",
|
||||||
"project.structure.side.proportion": "0.0"
|
"kotlin-language-version-configured": "true",
|
||||||
|
"last_opened_file_path": "D:/Workspace/MediaProcessing2/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract",
|
||||||
|
"project.structure.last.edited": "Modules",
|
||||||
|
"project.structure.proportion": "0.0",
|
||||||
|
"project.structure.side.proportion": "0.0"
|
||||||
}
|
}
|
||||||
}</component>
|
}]]></component>
|
||||||
<component name="RecentsManager">
|
<component name="RecentsManager">
|
||||||
<key name="CopyFile.RECENT_KEYS">
|
<key name="CopyFile.RECENT_KEYS">
|
||||||
<recent name="D:\Workspace\MediaProcessing2\shared\common\src\main\kotlin\no\iktdev\mediaprocessing\shared\common\contract" />
|
<recent name="D:\Workspace\MediaProcessing2\shared\common\src\main\kotlin\no\iktdev\mediaprocessing\shared\common\contract" />
|
||||||
@ -154,8 +171,8 @@
|
|||||||
<recent name="no.iktdev.mediaprocessing.shared.common" />
|
<recent name="no.iktdev.mediaprocessing.shared.common" />
|
||||||
</key>
|
</key>
|
||||||
</component>
|
</component>
|
||||||
<component name="RunManager" selected="Kotlin.UIApplicationKt">
|
<component name="RunManager" selected="Gradle.MediaProcessing2 [build]">
|
||||||
<configuration name="AudioArgumentsTest" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
<configuration name="FileNameParserTest" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
||||||
<ExternalSystemSettings>
|
<ExternalSystemSettings>
|
||||||
<option name="executionName" />
|
<option name="executionName" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
@ -166,9 +183,9 @@
|
|||||||
</option>
|
</option>
|
||||||
<option name="taskNames">
|
<option name="taskNames">
|
||||||
<list>
|
<list>
|
||||||
<option value=":apps:coordinator:test" />
|
<option value=":shared:common:test" />
|
||||||
<option value="--tests" />
|
<option value="--tests" />
|
||||||
<option value=""no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.streams.AudioArgumentsTest"" />
|
<option value=""no.iktdev.mediaprocessing.shared.common.parsing.FileNameParserTest"" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="vmOptions" />
|
<option name="vmOptions" />
|
||||||
@ -179,7 +196,7 @@
|
|||||||
<RunAsTest>true</RunAsTest>
|
<RunAsTest>true</RunAsTest>
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="AudioArgumentsTest.validateChecks3" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
<configuration name="FileNameParserTest.assertDotRemoval" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
||||||
<ExternalSystemSettings>
|
<ExternalSystemSettings>
|
||||||
<option name="executionName" />
|
<option name="executionName" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
@ -190,9 +207,9 @@
|
|||||||
</option>
|
</option>
|
||||||
<option name="taskNames">
|
<option name="taskNames">
|
||||||
<list>
|
<list>
|
||||||
<option value=":apps:coordinator:test" />
|
<option value=":shared:common:test" />
|
||||||
<option value="--tests" />
|
<option value="--tests" />
|
||||||
<option value=""no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.streams.AudioArgumentsTest.validateChecks3"" />
|
<option value=""no.iktdev.mediaprocessing.shared.common.parsing.FileNameParserTest.assertDotRemoval"" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="vmOptions" />
|
<option name="vmOptions" />
|
||||||
@ -203,7 +220,7 @@
|
|||||||
<RunAsTest>true</RunAsTest>
|
<RunAsTest>true</RunAsTest>
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="EncodeArgumentCreatorTaskTest" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
<configuration name="FileNameParserTest.assertTitleFails" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
||||||
<ExternalSystemSettings>
|
<ExternalSystemSettings>
|
||||||
<option name="executionName" />
|
<option name="executionName" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
@ -214,9 +231,9 @@
|
|||||||
</option>
|
</option>
|
||||||
<option name="taskNames">
|
<option name="taskNames">
|
||||||
<list>
|
<list>
|
||||||
<option value=":apps:coordinator:test" />
|
<option value=":shared:common:test" />
|
||||||
<option value="--tests" />
|
<option value="--tests" />
|
||||||
<option value=""no.iktdev.mediaprocessing.coordinator.tasks.event.ffmpeg.EncodeArgumentCreatorTaskTest"" />
|
<option value=""no.iktdev.mediaprocessing.shared.common.parsing.FileNameParserTest.assertTitleFails"" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="vmOptions" />
|
<option name="vmOptions" />
|
||||||
@ -272,20 +289,20 @@
|
|||||||
</method>
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
<list>
|
<list>
|
||||||
<item itemvalue="Gradle.AudioArgumentsTest" />
|
<item itemvalue="Gradle.FileNameParserTest" />
|
||||||
<item itemvalue="Gradle.AudioArgumentsTest.validateChecks3" />
|
<item itemvalue="Gradle.FileNameParserTest.assertDotRemoval" />
|
||||||
<item itemvalue="Gradle.EncodeArgumentCreatorTaskTest" />
|
<item itemvalue="Gradle.FileNameParserTest.assertTitleFails" />
|
||||||
<item itemvalue="Gradle.MediaProcessing2 [build]" />
|
<item itemvalue="Gradle.MediaProcessing2 [build]" />
|
||||||
<item itemvalue="Kotlin.Env - CoordinatorApplicationKt" />
|
<item itemvalue="Kotlin.Env - CoordinatorApplicationKt" />
|
||||||
<item itemvalue="Kotlin.UIApplicationKt" />
|
<item itemvalue="Kotlin.UIApplicationKt" />
|
||||||
</list>
|
</list>
|
||||||
<recent_temporary>
|
<recent_temporary>
|
||||||
<list>
|
<list>
|
||||||
<item itemvalue="Kotlin.UIApplicationKt" />
|
|
||||||
<item itemvalue="Gradle.MediaProcessing2 [build]" />
|
<item itemvalue="Gradle.MediaProcessing2 [build]" />
|
||||||
<item itemvalue="Gradle.AudioArgumentsTest" />
|
<item itemvalue="Gradle.FileNameParserTest.assertDotRemoval" />
|
||||||
<item itemvalue="Gradle.AudioArgumentsTest.validateChecks3" />
|
<item itemvalue="Gradle.FileNameParserTest" />
|
||||||
<item itemvalue="Gradle.EncodeArgumentCreatorTaskTest" />
|
<item itemvalue="Kotlin.UIApplicationKt" />
|
||||||
|
<item itemvalue="Gradle.FileNameParserTest.assertTitleFails" />
|
||||||
</list>
|
</list>
|
||||||
</recent_temporary>
|
</recent_temporary>
|
||||||
</component>
|
</component>
|
||||||
@ -298,8 +315,201 @@
|
|||||||
<option name="presentableId" value="Default" />
|
<option name="presentableId" value="Default" />
|
||||||
<updated>1722029797420</updated>
|
<updated>1722029797420</updated>
|
||||||
</task>
|
</task>
|
||||||
|
<task id="LOCAL−00001" summary="Exception on missing title..">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1723584577549</created>
|
||||||
|
<option name="number" value="LOCAL−00001" />
|
||||||
|
<option name="presentableId" value="LOCAL−00001" />
|
||||||
|
<updated>1723584577549</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00002" summary="Reduced logging and replaced with controller">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1724005100820</created>
|
||||||
|
<option name="number" value="LOCAL−00002" />
|
||||||
|
<option name="presentableId" value="LOCAL−00002" />
|
||||||
|
<updated>1724005100820</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00003" summary="Reduced logging and replaced with controller">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1724015265497</created>
|
||||||
|
<option name="number" value="LOCAL−00003" />
|
||||||
|
<option name="presentableId" value="LOCAL−00003" />
|
||||||
|
<updated>1724015265497</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00004" summary="Fix">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1724018515384</created>
|
||||||
|
<option name="number" value="LOCAL−00004" />
|
||||||
|
<option name="presentableId" value="LOCAL−00004" />
|
||||||
|
<updated>1724018515384</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00005" summary="Fix">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1724018747714</created>
|
||||||
|
<option name="number" value="LOCAL−00005" />
|
||||||
|
<option name="presentableId" value="LOCAL−00005" />
|
||||||
|
<updated>1724018747714</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00006" summary="Small tweaks">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1724197436532</created>
|
||||||
|
<option name="number" value="LOCAL−00006" />
|
||||||
|
<option name="presentableId" value="LOCAL−00006" />
|
||||||
|
<updated>1724197436532</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00007" summary="Log suppressing">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1724281074492</created>
|
||||||
|
<option name="number" value="LOCAL−00007" />
|
||||||
|
<option name="presentableId" value="LOCAL−00007" />
|
||||||
|
<updated>1724281074492</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00008" summary="Log suppressing">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1724283312428</created>
|
||||||
|
<option name="number" value="LOCAL−00008" />
|
||||||
|
<option name="presentableId" value="LOCAL−00008" />
|
||||||
|
<updated>1724283312428</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00009" summary="Database connect if not connected">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1728410705301</created>
|
||||||
|
<option name="number" value="LOCAL−00009" />
|
||||||
|
<option name="presentableId" value="LOCAL−00009" />
|
||||||
|
<updated>1728410705301</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00010" summary="Updated py">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729126953490</created>
|
||||||
|
<option name="number" value="LOCAL−00010" />
|
||||||
|
<option name="presentableId" value="LOCAL−00010" />
|
||||||
|
<updated>1729126953490</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00011" summary="Default">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729127287407</created>
|
||||||
|
<option name="number" value="LOCAL−00011" />
|
||||||
|
<option name="presentableId" value="LOCAL−00011" />
|
||||||
|
<updated>1729127287407</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00012" summary="Fix for locked loop">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729127765449</created>
|
||||||
|
<option name="number" value="LOCAL−00012" />
|
||||||
|
<option name="presentableId" value="LOCAL−00012" />
|
||||||
|
<updated>1729127765449</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00013" summary="Fix for missing assignment">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729128050503</created>
|
||||||
|
<option name="number" value="LOCAL−00013" />
|
||||||
|
<option name="presentableId" value="LOCAL−00013" />
|
||||||
|
<updated>1729128050503</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00014" summary="Removing database closer">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729128276481</created>
|
||||||
|
<option name="number" value="LOCAL−00014" />
|
||||||
|
<option name="presentableId" value="LOCAL−00014" />
|
||||||
|
<updated>1729128276481</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00015" summary="Logging">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729180125525</created>
|
||||||
|
<option name="number" value="LOCAL−00015" />
|
||||||
|
<option name="presentableId" value="LOCAL−00015" />
|
||||||
|
<updated>1729180125525</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00016" summary="Logging">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729722098624</created>
|
||||||
|
<option name="number" value="LOCAL−00016" />
|
||||||
|
<option name="presentableId" value="LOCAL−00016" />
|
||||||
|
<updated>1729722098624</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00017" summary="Logging">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729722590315</created>
|
||||||
|
<option name="number" value="LOCAL−00017" />
|
||||||
|
<option name="presentableId" value="LOCAL−00017" />
|
||||||
|
<updated>1729722590315</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00018" summary="Logging">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1729723155814</created>
|
||||||
|
<option name="number" value="LOCAL−00018" />
|
||||||
|
<option name="presentableId" value="LOCAL−00018" />
|
||||||
|
<updated>1729723155814</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00019" summary="Disabling metadata timeout">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1730902509789</created>
|
||||||
|
<option name="number" value="LOCAL−00019" />
|
||||||
|
<option name="presentableId" value="LOCAL−00019" />
|
||||||
|
<updated>1730902509789</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00020" summary="Logging and ping">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1730935750213</created>
|
||||||
|
<option name="number" value="LOCAL−00020" />
|
||||||
|
<option name="presentableId" value="LOCAL−00020" />
|
||||||
|
<updated>1730935750213</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00021" summary="Error handling">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1730936604956</created>
|
||||||
|
<option name="number" value="LOCAL−00021" />
|
||||||
|
<option name="presentableId" value="LOCAL−00021" />
|
||||||
|
<updated>1730936604956</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00022" summary="Fixed placement">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1730937000591</created>
|
||||||
|
<option name="number" value="LOCAL−00022" />
|
||||||
|
<option name="presentableId" value="LOCAL−00022" />
|
||||||
|
<updated>1730937000591</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL−00023" summary="Closing connection after every query">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1734554387826</created>
|
||||||
|
<option name="number" value="LOCAL−00023" />
|
||||||
|
<option name="presentableId" value="LOCAL−00023" />
|
||||||
|
<updated>1734554387826</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="24" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="Vcs.Log.Tabs.Properties">
|
||||||
|
<option name="TAB_STATES">
|
||||||
|
<map>
|
||||||
|
<entry key="MAIN">
|
||||||
|
<value>
|
||||||
|
<State />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="VcsManagerConfiguration">
|
||||||
|
<MESSAGE value="Exception on missing title.." />
|
||||||
|
<MESSAGE value="Reduced logging and replaced with controller" />
|
||||||
|
<MESSAGE value="Fix" />
|
||||||
|
<MESSAGE value="Small tweaks" />
|
||||||
|
<MESSAGE value="Log suppressing" />
|
||||||
|
<MESSAGE value="Database connect if not connected" />
|
||||||
|
<MESSAGE value="Updated py" />
|
||||||
|
<MESSAGE value="Default" />
|
||||||
|
<MESSAGE value="Fix for locked loop" />
|
||||||
|
<MESSAGE value="Fix for missing assignment" />
|
||||||
|
<MESSAGE value="Removing database closer" />
|
||||||
|
<MESSAGE value="Logging" />
|
||||||
|
<MESSAGE value="Disabling metadata timeout" />
|
||||||
|
<MESSAGE value="Logging and ping" />
|
||||||
|
<MESSAGE value="Error handling" />
|
||||||
|
<MESSAGE value="Fixed placement" />
|
||||||
|
<MESSAGE value="Closing connection after every query" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Closing connection after every query" />
|
||||||
|
</component>
|
||||||
<component name="XDebuggerManager">
|
<component name="XDebuggerManager">
|
||||||
<breakpoint-manager>
|
<breakpoint-manager>
|
||||||
<breakpoints>
|
<breakpoints>
|
||||||
@ -308,6 +518,61 @@
|
|||||||
<line>23</line>
|
<line>23</line>
|
||||||
<option name="timeStamp" value="1" />
|
<option name="timeStamp" value="1" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/eventi/src/main/kotlin/no/iktdev/eventi/implementations/EventCoordinator.kt</url>
|
||||||
|
<line>133</line>
|
||||||
|
<option name="timeStamp" value="17" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/eventi/src/main/kotlin/no/iktdev/eventi/implementations/EventCoordinator.kt</url>
|
||||||
|
<line>130</line>
|
||||||
|
<option name="timeStamp" value="18" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/eventi/src/main/kotlin/no/iktdev/eventi/implementations/EventCoordinator.kt</url>
|
||||||
|
<line>131</line>
|
||||||
|
<option name="timeStamp" value="19" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/common/src/test/kotlin/no/iktdev/mediaprocessing/shared/common/parsing/FileNameParserTest.kt</url>
|
||||||
|
<line>44</line>
|
||||||
|
<option name="timeStamp" value="20" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/common/src/test/kotlin/no/iktdev/mediaprocessing/shared/common/parsing/FileNameParserTest.kt</url>
|
||||||
|
<line>43</line>
|
||||||
|
<option name="timeStamp" value="21" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/parsing/FileNameParser.kt</url>
|
||||||
|
<line>22</line>
|
||||||
|
<option name="timeStamp" value="22" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/parsing/FileNameParser.kt</url>
|
||||||
|
<line>23</line>
|
||||||
|
<option name="timeStamp" value="23" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/parsing/FileNameParser.kt</url>
|
||||||
|
<line>24</line>
|
||||||
|
<option name="timeStamp" value="25" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/parsing/FileNameParser.kt</url>
|
||||||
|
<line>25</line>
|
||||||
|
<option name="timeStamp" value="26" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/parsing/FileNameParser.kt</url>
|
||||||
|
<line>40</line>
|
||||||
|
<option name="timeStamp" value="27" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/parsing/FileNameParser.kt</url>
|
||||||
|
<line>41</line>
|
||||||
|
<option name="timeStamp" value="28" />
|
||||||
|
</line-breakpoint>
|
||||||
</breakpoints>
|
</breakpoints>
|
||||||
</breakpoint-manager>
|
</breakpoint-manager>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@ -72,6 +72,7 @@ class ConvertService(
|
|||||||
|
|
||||||
override fun onCompleted(inputFile: String, outputFiles: List<String>) {
|
override fun onCompleted(inputFile: String, outputFiles: List<String>) {
|
||||||
val task = assignedTask ?: return
|
val task = assignedTask ?: return
|
||||||
|
val taskData: ConvertData = task.data as ConvertData
|
||||||
log.info { "Convert completed for ${task.referenceId}" }
|
log.info { "Convert completed for ${task.referenceId}" }
|
||||||
val claimSuccessful = taskManager.markTaskAsCompleted(task.referenceId, task.eventId)
|
val claimSuccessful = taskManager.markTaskAsCompleted(task.referenceId, task.eventId)
|
||||||
|
|
||||||
@ -95,6 +96,7 @@ class ConvertService(
|
|||||||
source = getProducerName()
|
source = getProducerName()
|
||||||
),
|
),
|
||||||
data = ConvertedData(
|
data = ConvertedData(
|
||||||
|
language = taskData.language,
|
||||||
outputFiles = outputFiles
|
outputFiles = outputFiles
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|||||||
@ -37,7 +37,7 @@ dependencies {
|
|||||||
implementation("org.json:json:20210307")
|
implementation("org.json:json:20210307")
|
||||||
|
|
||||||
implementation("no.iktdev:exfl:0.0.16-SNAPSHOT")
|
implementation("no.iktdev:exfl:0.0.16-SNAPSHOT")
|
||||||
implementation("no.iktdev.streamit.library:streamit-library-db:0.0.6-alpha27")
|
implementation("no.iktdev.streamit.library:streamit-library-db:1.0.0-alpha11")
|
||||||
|
|
||||||
|
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
|
||||||
|
|||||||
@ -7,22 +7,17 @@ import no.iktdev.mediaprocessing.coordinator.Coordinator
|
|||||||
import no.iktdev.mediaprocessing.coordinator.CoordinatorEventListener
|
import no.iktdev.mediaprocessing.coordinator.CoordinatorEventListener
|
||||||
import no.iktdev.mediaprocessing.coordinator.getStoreDatabase
|
import no.iktdev.mediaprocessing.coordinator.getStoreDatabase
|
||||||
import no.iktdev.eventi.database.executeOrException
|
import no.iktdev.eventi.database.executeOrException
|
||||||
import no.iktdev.eventi.database.executeWithStatus
|
|
||||||
import no.iktdev.eventi.database.withTransaction
|
import no.iktdev.eventi.database.withTransaction
|
||||||
|
import no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.store.*
|
||||||
|
import no.iktdev.mediaprocessing.coordinator.tasksV2.validator.CompletionValidator
|
||||||
import no.iktdev.mediaprocessing.shared.common.parsing.NameHelper
|
import no.iktdev.mediaprocessing.shared.common.parsing.NameHelper
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.data.*
|
import no.iktdev.mediaprocessing.shared.common.contract.data.*
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.dto.StartOperationEvents
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.dto.SubtitleFormats
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.reader.*
|
import no.iktdev.mediaprocessing.shared.common.contract.reader.*
|
||||||
import no.iktdev.streamit.library.db.query.CatalogQuery
|
|
||||||
import no.iktdev.streamit.library.db.query.GenreQuery
|
|
||||||
import no.iktdev.streamit.library.db.query.SubtitleQuery
|
|
||||||
import no.iktdev.streamit.library.db.query.SummaryQuery
|
import no.iktdev.streamit.library.db.query.SummaryQuery
|
||||||
import no.iktdev.streamit.library.db.tables.catalog
|
import no.iktdev.streamit.library.db.tables.catalog
|
||||||
import no.iktdev.streamit.library.db.tables.titles
|
import no.iktdev.streamit.library.db.tables.titles
|
||||||
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
||||||
import org.jetbrains.exposed.sql.and
|
|
||||||
import org.jetbrains.exposed.sql.insertIgnore
|
import org.jetbrains.exposed.sql.insertIgnore
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
@ -64,104 +59,6 @@ class CompletedTaskListener: CoordinatorEventListener() {
|
|||||||
Events.EventWorkExtractPerformed
|
Events.EventWorkExtractPerformed
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether it requires encode or extract or both, and it has created events with args
|
|
||||||
*/
|
|
||||||
fun req1(started: MediaProcessStartEvent, events: List<Event>): Boolean {
|
|
||||||
val encodeFulfilledOrSkipped = if (started.data?.operations?.contains(StartOperationEvents.ENCODE) == true) {
|
|
||||||
events.any { it.eventType == Events.EventMediaParameterEncodeCreated }
|
|
||||||
} else true
|
|
||||||
|
|
||||||
val extractFulfilledOrSkipped = if (started.data?.operations?.contains(StartOperationEvents.EXTRACT) == true) {
|
|
||||||
events.any { it.eventType == Events.EventMediaParameterExtractCreated }
|
|
||||||
} else true
|
|
||||||
|
|
||||||
if (!encodeFulfilledOrSkipped || !extractFulfilledOrSkipped) {
|
|
||||||
return false
|
|
||||||
} else return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether work that was supposed to be created has been created.
|
|
||||||
* Checks if all subtitles that can be processed has been created if convert is set.
|
|
||||||
*/
|
|
||||||
fun req2(operations: List<StartOperationEvents>, events: List<Event>): Boolean {
|
|
||||||
if (StartOperationEvents.ENCODE in operations) {
|
|
||||||
val encodeParamter = events.find { it.eventType == Events.EventMediaParameterEncodeCreated }?.az<EncodeArgumentCreatedEvent>()
|
|
||||||
val encodeWork = events.find { it.eventType == Events.EventWorkEncodeCreated }
|
|
||||||
if (encodeParamter?.isSuccessful() == true && (encodeWork == null))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val extractParamter = events.find { it.eventType == Events.EventMediaParameterExtractCreated }?.az<ExtractArgumentCreatedEvent>()
|
|
||||||
val extractWork = events.filter { it.eventType == Events.EventWorkExtractCreated }
|
|
||||||
if (StartOperationEvents.EXTRACT in operations) {
|
|
||||||
if (extractParamter?.isSuccessful() == true && extractParamter.data?.size != extractWork.size)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StartOperationEvents.CONVERT in operations) {
|
|
||||||
val convertWork = events.filter { it.eventType == Events.EventWorkConvertCreated }
|
|
||||||
|
|
||||||
val supportedSubtitleFormats = SubtitleFormats.entries.map { it.name }
|
|
||||||
val eventsSupportsConvert = extractWork.filter { it.data is ExtractArgumentData }
|
|
||||||
.filter { (it.dataAs<ExtractArgumentData>()?.outputFile?.let { f -> File(f).extension.uppercase() } in supportedSubtitleFormats) }
|
|
||||||
|
|
||||||
if (convertWork.size != eventsSupportsConvert.size)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether all work that has been created has been completed
|
|
||||||
*/
|
|
||||||
fun req3(operations: List<StartOperationEvents>, events: List<Event>): Boolean {
|
|
||||||
if (StartOperationEvents.ENCODE in operations) {
|
|
||||||
val encodeWork = events.filter { it.eventType == Events.EventWorkEncodeCreated }
|
|
||||||
val encodePerformed = events.filter { it.eventType == Events.EventWorkEncodePerformed }
|
|
||||||
if (encodePerformed.size < encodeWork.size)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StartOperationEvents.EXTRACT in operations) {
|
|
||||||
val extractWork = events.filter { it.eventType == Events.EventWorkExtractCreated }
|
|
||||||
val extractPerformed = events.filter { it.eventType == Events.EventWorkExtractPerformed }
|
|
||||||
if (extractPerformed.size < extractWork.size)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StartOperationEvents.CONVERT in operations) {
|
|
||||||
val convertWork = events.filter { it.eventType == Events.EventWorkConvertCreated }
|
|
||||||
val convertPerformed = events.filter { it.eventType == Events.EventWorkConvertPerformed }
|
|
||||||
if (convertPerformed.size < convertWork.size)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if metadata has cover, if so, 2 events are expected
|
|
||||||
*/
|
|
||||||
fun req4(events: List<Event>): Boolean {
|
|
||||||
val metadata = events.find { it.eventType == Events.EventMediaMetadataSearchPerformed }
|
|
||||||
if (metadata?.isSuccessful() != true) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasCover = metadata.dataAs<pyMetadata>()?.cover != null
|
|
||||||
if (hasCover == false) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (events.any { it.eventType == Events.EventMediaReadOutCover } && events.any { it.eventType == Events.EventWorkDownloadCoverPerformed }) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun isPrerequisitesFulfilled(incomingEvent: Event, events: List<Event>): Boolean {
|
override fun isPrerequisitesFulfilled(incomingEvent: Event, events: List<Event>): Boolean {
|
||||||
val started = events.find { it.eventType == Events.EventMediaProcessStarted }?.az<MediaProcessStartEvent>()
|
val started = events.find { it.eventType == Events.EventMediaProcessStarted }?.az<MediaProcessStartEvent>()
|
||||||
@ -171,104 +68,28 @@ class CompletedTaskListener: CoordinatorEventListener() {
|
|||||||
}
|
}
|
||||||
val viableEvents = events.filter { it.isSuccessful() }
|
val viableEvents = events.filter { it.isSuccessful() }
|
||||||
|
|
||||||
|
if (!CompletionValidator.req1(started, events)) {
|
||||||
if (!req1(started, events)) {
|
|
||||||
//log.info { "${this::class.java.simpleName} Failed Req1" }
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req2(started.data?.operations ?: emptyList(), viableEvents)) {
|
if (!CompletionValidator.req2(started.data?.operations ?: emptyList(), viableEvents)) {
|
||||||
//log.info { "${this::class.java.simpleName} Failed Req2" }
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req3(started.data?.operations ?: emptyList(), events)) {
|
if (!CompletionValidator.req3(started.data?.operations ?: emptyList(), events)) {
|
||||||
//log.info { "${this::class.java.simpleName} Failed Req3" }
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req4(events)) {
|
if (!CompletionValidator.req4(events)) {
|
||||||
log.info { "${this::class.java.simpleName} Failed Req4" }
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return super.isPrerequisitesFulfilled(incomingEvent, events)
|
return super.isPrerequisitesFulfilled(incomingEvent, events)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMetadata(events: List<Event>): MetadataDto? {
|
|
||||||
val baseInfo = events.find { it.eventType == Events.EventMediaReadBaseInfoPerformed }?.az<BaseInfoEvent>()
|
|
||||||
val mediaInfo = events.find { it.eventType == Events.EventMediaReadOutNameAndType }?.az<MediaOutInformationConstructedEvent>()
|
|
||||||
val metadataInfo = events.find { it.eventType == Events.EventMediaMetadataSearchPerformed }?.az<MediaMetadataReceivedEvent>()
|
|
||||||
val coverInfo = events.find { it.eventType == Events.EventWorkDownloadCoverPerformed }?.az<MediaCoverDownloadedEvent>()
|
|
||||||
val coverTask = events.find { it.eventType == Events.EventMediaReadOutCover }?.az<MediaCoverInfoReceivedEvent>()
|
|
||||||
|
|
||||||
if (baseInfo == null) {
|
|
||||||
log.info { "Cant find BaseInfoEvent on ${Events.EventMediaReadBaseInfoPerformed}" }
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mediaInfo == null) {
|
|
||||||
log.info { "Cant find MediaOutInformationConstructedEvent on ${Events.EventMediaReadOutNameAndType}" }
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadataInfo == null) {
|
|
||||||
log.info { "Cant find MediaMetadataReceivedEvent on ${Events.EventMediaMetadataSearchPerformed}" }
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coverTask?.isSkipped() == false && coverInfo == null) {
|
|
||||||
log.info { "Cant find MediaCoverDownloadedEvent on ${Events.EventWorkDownloadCoverPerformed}" }
|
|
||||||
}
|
|
||||||
|
|
||||||
val mediaInfoData = mediaInfo.data?.toValueObject()
|
|
||||||
val baseInfoData = baseInfo.data
|
|
||||||
val metadataInfoData = metadataInfo.data
|
|
||||||
|
|
||||||
|
|
||||||
val collection = mediaInfo.data?.outDirectory?.let { File(it).name } ?: baseInfoData?.title
|
|
||||||
|
|
||||||
val coverFileName = coverInfo?.data?.absoluteFilePath?.let {
|
|
||||||
File(it).name
|
|
||||||
}
|
|
||||||
|
|
||||||
return MetadataDto(
|
|
||||||
title = mediaInfoData?.title ?: baseInfoData?.title ?: metadataInfoData?.title ?: return null,
|
|
||||||
collection = collection ?: return null,
|
|
||||||
cover = coverFileName,
|
|
||||||
type = metadataInfoData?.type ?: mediaInfoData?.type ?: return null,
|
|
||||||
summary = metadataInfoData?.summary?.filter {it.summary != null }?.map { SummaryInfo(language = it.language, summary = it.summary!! ) } ?: emptyList(),
|
|
||||||
genres = metadataInfoData?.genres ?: emptyList(),
|
|
||||||
titles = (metadataInfoData?.altTitle ?: emptyList()) + listOfNotNull(mediaInfoData?.title, baseInfoData?.title)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getGenres(events: List<Event>): List<String> {
|
|
||||||
val metadataInfo = events.find { it.eventType == Events.EventMediaMetadataSearchPerformed }?.az<MediaMetadataReceivedEvent>()
|
|
||||||
return metadataInfo?.data?.genres ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSubtitles(metadataDto: MetadataDto?, events: List<Event>): List<SubtitlesDto> {
|
|
||||||
val extracted = events.filter { it.eventType == Events.EventWorkExtractPerformed }.mapNotNull { it.dataAs<ExtractedData>() }
|
|
||||||
val converted = events.filter { it.eventType == Events.EventWorkConvertPerformed }.mapNotNull { it.dataAs<ConvertedData>() }
|
|
||||||
|
|
||||||
val outFiles = extracted.map { it.outputFile } + converted.flatMap { it.outputFiles }
|
|
||||||
|
|
||||||
return outFiles.map {
|
|
||||||
val subtitleFile = File(it)
|
|
||||||
SubtitlesDto(
|
|
||||||
collection = metadataDto?.collection ?: subtitleFile.parentFile.parentFile.name,
|
|
||||||
language = subtitleFile.parentFile.name,
|
|
||||||
subtitleFile = subtitleFile.name,
|
|
||||||
format = subtitleFile.extension.uppercase(),
|
|
||||||
associatedWithVideo = subtitleFile.nameWithoutExtension,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getVideo(events: List<Event>): VideoDetails? {
|
fun getVideo(events: List<Event>): VideoDetails? {
|
||||||
val mediaInfo = events.find { it.eventType == Events.EventMediaReadOutNameAndType }?.az<MediaOutInformationConstructedEvent>()
|
val mediaInfo = events.find { it.eventType == Events.EventMediaReadOutNameAndType }
|
||||||
|
?.az<MediaOutInformationConstructedEvent>()
|
||||||
val encoded = events.find { it.eventType == Events.EventWorkEncodePerformed }?.dataAs<EncodedData>()?.outputFile
|
val encoded = events.find { it.eventType == Events.EventWorkEncodePerformed }?.dataAs<EncodedData>()?.outputFile
|
||||||
if (encoded == null) {
|
if (encoded == null) {
|
||||||
log.warn { "No encode no video details!" }
|
log.warn { "No encode no video details!" }
|
||||||
@ -290,120 +111,8 @@ class CompletedTaskListener: CoordinatorEventListener() {
|
|||||||
return details
|
return details
|
||||||
}
|
}
|
||||||
|
|
||||||
fun storeSubtitles(subtitles: List<SubtitlesDto>) {
|
|
||||||
subtitles.forEach { subtitle ->
|
|
||||||
subtitle to executeWithStatus(getStoreDatabase()) {
|
|
||||||
SubtitleQuery(
|
|
||||||
collection = subtitle.collection,
|
|
||||||
associatedWithVideo = subtitle.associatedWithVideo,
|
|
||||||
language = subtitle.language,
|
|
||||||
format = subtitle.format,
|
|
||||||
file = subtitle.subtitleFile
|
|
||||||
).insert()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun storeTitles(usedTitle: String, metadata: MetadataDto) {
|
|
||||||
try {
|
|
||||||
withTransaction(getStoreDatabase()) {
|
|
||||||
titles.insertIgnore {
|
|
||||||
it[masterTitle] = metadata.collection
|
|
||||||
it[title] = NameHelper.normalize(usedTitle)
|
|
||||||
it[type] = 1
|
|
||||||
}
|
|
||||||
titles.insertIgnore {
|
|
||||||
it[masterTitle] = usedTitle
|
|
||||||
it[title] = NameHelper.normalize(usedTitle)
|
|
||||||
it[type] = 2
|
|
||||||
}
|
|
||||||
metadata.titles.forEach { title ->
|
|
||||||
titles.insertIgnore {
|
|
||||||
it[masterTitle] = usedTitle
|
|
||||||
it[titles.title] = title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun storeMetadata(catalogId: Int, metadata: MetadataDto) {
|
|
||||||
if (!metadata.cover.isNullOrBlank()) {
|
|
||||||
withTransaction(getStoreDatabase()) {
|
|
||||||
val storedCatalogCover = catalog.select {
|
|
||||||
(catalog.id eq catalogId)
|
|
||||||
}.map { it[catalog.cover] }.firstOrNull()
|
|
||||||
if (storedCatalogCover.isNullOrBlank()) {
|
|
||||||
catalog.update({
|
|
||||||
catalog.id eq catalogId
|
|
||||||
}) {
|
|
||||||
it[catalog.cover] = metadata.cover
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
metadata.summary.forEach {
|
|
||||||
val result = executeOrException(getStoreDatabase().database) {
|
|
||||||
SummaryQuery(
|
|
||||||
cid = catalogId,
|
|
||||||
language = it.language,
|
|
||||||
description = it.summary
|
|
||||||
).insert()
|
|
||||||
}
|
|
||||||
val ignoreException = result?.cause is SQLIntegrityConstraintViolationException && (result as ExposedSQLException).errorCode == 1062
|
|
||||||
if (!ignoreException) {
|
|
||||||
result?.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun storeAndGetGenres(genres: List<String>): String? {
|
|
||||||
return withTransaction(getStoreDatabase()) {
|
|
||||||
val gq = GenreQuery( *genres.toTypedArray() )
|
|
||||||
gq.insertAndGetIds()
|
|
||||||
gq.getIds().joinToString(",")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun storeCatalog(metadata: MetadataDto, videoDetails: VideoDetails, genres: String?): Int? {
|
|
||||||
val precreatedCatalogQuery = CatalogQuery(
|
|
||||||
title = NameHelper.normalize(metadata.title),
|
|
||||||
cover = metadata.cover,
|
|
||||||
type = metadata.type,
|
|
||||||
collection = metadata.collection,
|
|
||||||
genres = genres
|
|
||||||
)
|
|
||||||
|
|
||||||
val result = when (videoDetails.type) {
|
|
||||||
"serie" -> {
|
|
||||||
val serieInfo = videoDetails.serieInfo ?: throw RuntimeException("SerieInfo missing in VideoDetails for Serie! ${videoDetails.fileName}")
|
|
||||||
executeOrException {
|
|
||||||
precreatedCatalogQuery.insertWithSerie(
|
|
||||||
episodeTitle = serieInfo.episodeTitle ?: "",
|
|
||||||
videoFile = videoDetails.fileName,
|
|
||||||
episode = serieInfo.episodeNumber,
|
|
||||||
season = serieInfo.seasonNumber
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"movie" -> {
|
|
||||||
executeOrException {
|
|
||||||
precreatedCatalogQuery.insertWithMovie(videoDetails.fileName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw RuntimeException("${videoDetails.type} is not supported!")
|
|
||||||
}
|
|
||||||
val ignoreException = result?.cause is SQLIntegrityConstraintViolationException && (result as ExposedSQLException).errorCode == 1062
|
|
||||||
return withTransaction(getStoreDatabase()) {
|
|
||||||
precreatedCatalogQuery.getId()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun shouldIProcessAndHandleEvent(incomingEvent: Event, events: List<Event>): Boolean {
|
override fun shouldIProcessAndHandleEvent(incomingEvent: Event, events: List<Event>): Boolean {
|
||||||
val result = super.shouldIProcessAndHandleEvent(incomingEvent, events)
|
val result = super.shouldIProcessAndHandleEvent(incomingEvent, events)
|
||||||
return result
|
return result
|
||||||
@ -413,27 +122,63 @@ class CompletedTaskListener: CoordinatorEventListener() {
|
|||||||
val event = incomingEvent.consume() ?: return
|
val event = incomingEvent.consume() ?: return
|
||||||
active = true
|
active = true
|
||||||
|
|
||||||
val metadata = getMetadata(events)
|
val mediaInfo: ComposedMediaInfo = composeMediaInfo(events) ?: run {
|
||||||
val genres = getGenres(events)
|
log.error { "Unable to compose media info for ${event.referenceId()}" }
|
||||||
val subtitles = getSubtitles(metadata, events)
|
return
|
||||||
val video = getVideo(events)
|
}
|
||||||
|
|
||||||
|
val existingTitles = ContentTitleStore.findMasterTitles(mediaInfo.titles)
|
||||||
|
|
||||||
|
val usableCollection: String = if (existingTitles.isNotEmpty())
|
||||||
|
ContentCatalogStore.getCollectionByTitleAndType(mediaInfo.type, existingTitles) ?: run {
|
||||||
|
log.warn { "Did not receive collection based on titles provided in list ${existingTitles.joinToString(",")}, falling back to fallbackCollection: ${mediaInfo.fallbackCollection}" }
|
||||||
|
mediaInfo.fallbackCollection
|
||||||
|
} else mediaInfo.fallbackCollection
|
||||||
|
|
||||||
|
val mover = ContentCompletionMover(usableCollection, events)
|
||||||
|
val newVideoPath = mover.moveVideo()
|
||||||
|
val newCoverPath = mover.moveCover()
|
||||||
|
val newSubtitles = mover.moveSubtitles()
|
||||||
|
|
||||||
|
val genreIdsForCatalog = ContentGenresStore.storeAndGetIds(mediaInfo.genres)
|
||||||
|
|
||||||
|
|
||||||
val storedGenres = storeAndGetGenres(genres)
|
val catalogId = ContentCatalogStore.storeCatalog(
|
||||||
val catalogId = if (metadata != null && video != null) {
|
title = mediaInfo.title,
|
||||||
storeCatalog(metadata, video, storedGenres)
|
collection = usableCollection,
|
||||||
} else null
|
type = mediaInfo.type,
|
||||||
|
cover = newCoverPath?.second?.let { dp -> File(dp).name },
|
||||||
|
genres = genreIdsForCatalog,
|
||||||
|
)
|
||||||
|
|
||||||
|
getVideo(events)?.let { video ->
|
||||||
|
ContentCatalogStore.storeMedia(
|
||||||
|
title = mediaInfo.title,
|
||||||
|
collection = usableCollection,
|
||||||
|
type = mediaInfo.type,
|
||||||
|
videoDetails = video
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val storedSubtitles = newSubtitles?.let { subtitles ->
|
||||||
storeSubtitles(subtitles)
|
subtitles.mapNotNull {
|
||||||
metadata?.let {
|
ContentSubtitleStore.storeSubtitles(
|
||||||
storeTitles(metadata = metadata, usedTitle = metadata.title)
|
collection = usableCollection,
|
||||||
catalogId?.let { id ->
|
language = it.language,
|
||||||
storeMetadata(catalogId = id, metadata = it)
|
destinationFile = it.destination
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catalogId?.let { cid ->
|
||||||
|
mediaInfo.summaries.forEach {
|
||||||
|
ContentMetadataStore.storeSummary(cid, it)
|
||||||
|
}
|
||||||
|
ContentTitleStore.store(mediaInfo.title, mediaInfo.titles)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!doNotProduceComplete) {
|
if (!doNotProduceComplete) {
|
||||||
onProduceEvent(MediaProcessCompletedEvent(
|
onProduceEvent(MediaProcessCompletedEvent(
|
||||||
metadata = event.makeDerivedEventInfo(EventStatus.Success, getProducerName()),
|
metadata = event.makeDerivedEventInfo(EventStatus.Success, getProducerName()),
|
||||||
@ -448,4 +193,57 @@ class CompletedTaskListener: CoordinatorEventListener() {
|
|||||||
active = false
|
active = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal data class ComposedMediaInfo(
|
||||||
|
val title: String,
|
||||||
|
val fallbackCollection: String,
|
||||||
|
|
||||||
|
val titles: List<String>,
|
||||||
|
val type: String,
|
||||||
|
val summaries: List<SummaryInfo>,
|
||||||
|
val genres: List<String>
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun composeMediaInfo(events: List<Event>): ComposedMediaInfo? {
|
||||||
|
val baseInfo =
|
||||||
|
events.find { it.eventType == Events.EventMediaReadBaseInfoPerformed }?.az<BaseInfoEvent>()?.let {
|
||||||
|
it.data
|
||||||
|
} ?: run {
|
||||||
|
log.info { "Cant find BaseInfoEvent on ${Events.EventMediaReadBaseInfoPerformed}" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val metadataInfo =
|
||||||
|
events.find { it.eventType == Events.EventMediaMetadataSearchPerformed }?.az<MediaMetadataReceivedEvent>()?.data
|
||||||
|
?: run {
|
||||||
|
log.info { "Cant find MediaMetadataReceivedEvent on ${Events.EventMediaMetadataSearchPerformed}" }
|
||||||
|
null
|
||||||
|
}
|
||||||
|
val mediaInfo: MediaInfo = events.find { it.eventType == Events.EventMediaReadOutNameAndType }
|
||||||
|
?.az<MediaOutInformationConstructedEvent>()?.let {
|
||||||
|
it.data?.toValueObject()
|
||||||
|
} ?: run {
|
||||||
|
log.info { "Cant find MediaOutInformationConstructedEvent on ${Events.EventMediaReadOutNameAndType}" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val summaries = metadataInfo?.summary?.filter { it.summary != null }
|
||||||
|
?.map { SummaryInfo(language = it.language, summary = it.summary!!) } ?: emptyList()
|
||||||
|
|
||||||
|
val titles: MutableList<String> = mutableListOf(mediaInfo.title)
|
||||||
|
metadataInfo?.let {
|
||||||
|
titles.addAll(it.altTitle)
|
||||||
|
titles.add(it.title)
|
||||||
|
titles.add(NameHelper.normalize(it.title))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ComposedMediaInfo(
|
||||||
|
title = NameHelper.normalize(metadataInfo?.title ?: mediaInfo.title),
|
||||||
|
fallbackCollection = baseInfo.title,
|
||||||
|
titles = titles,
|
||||||
|
type = metadataInfo?.type ?: mediaInfo.type,
|
||||||
|
summaries = summaries,
|
||||||
|
genres = metadataInfo?.genres ?: emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -63,8 +63,13 @@ class ConvertWorkTaskListener: WorkTaskListener() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var language: String? = null
|
||||||
|
|
||||||
|
|
||||||
val file = if (event.eventType == Events.EventWorkExtractPerformed) {
|
val file = if (event.eventType == Events.EventWorkExtractPerformed) {
|
||||||
event.az<ExtractWorkPerformedEvent>()?.data?.outputFile
|
val foundEvent = event.az<ExtractWorkPerformedEvent>()?.data
|
||||||
|
language = foundEvent?.language
|
||||||
|
foundEvent?.outputFile
|
||||||
} else if (event.eventType == Events.EventMediaProcessStarted) {
|
} else if (event.eventType == Events.EventMediaProcessStarted) {
|
||||||
val startEvent = event.az<MediaProcessStartEvent>()?.data
|
val startEvent = event.az<MediaProcessStartEvent>()?.data
|
||||||
if (startEvent?.operations?.isOnly(StartOperationEvents.CONVERT) == true) {
|
if (startEvent?.operations?.isOnly(StartOperationEvents.CONVERT) == true) {
|
||||||
@ -77,6 +82,15 @@ class ConvertWorkTaskListener: WorkTaskListener() {
|
|||||||
|
|
||||||
|
|
||||||
val convertFile = file?.let { File(it) }
|
val convertFile = file?.let { File(it) }
|
||||||
|
if (language.isNullOrEmpty()) {
|
||||||
|
convertFile?.parentFile?.nameWithoutExtension?.let {
|
||||||
|
if (it.length == 3) {
|
||||||
|
language = it.lowercase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (convertFile == null || !convertFile.exists()) {
|
if (convertFile == null || !convertFile.exists()) {
|
||||||
onProduceEvent(ConvertWorkCreatedEvent(
|
onProduceEvent(ConvertWorkCreatedEvent(
|
||||||
metadata = event.makeDerivedEventInfo(EventStatus.Failed, getProducerName())
|
metadata = event.makeDerivedEventInfo(EventStatus.Failed, getProducerName())
|
||||||
@ -84,6 +98,7 @@ class ConvertWorkTaskListener: WorkTaskListener() {
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
val convertData = ConvertData(
|
val convertData = ConvertData(
|
||||||
|
language = language ?: "unk",
|
||||||
inputFile = convertFile.absolutePath,
|
inputFile = convertFile.absolutePath,
|
||||||
outputFileName = convertFile.nameWithoutExtension,
|
outputFileName = convertFile.nameWithoutExtension,
|
||||||
outputDirectory = convertFile.parentFile.absolutePath,
|
outputDirectory = convertFile.parentFile.absolutePath,
|
||||||
|
|||||||
@ -6,9 +6,11 @@ import no.iktdev.eventi.core.ConsumableEvent
|
|||||||
import no.iktdev.eventi.core.WGson
|
import no.iktdev.eventi.core.WGson
|
||||||
import no.iktdev.eventi.data.EventStatus
|
import no.iktdev.eventi.data.EventStatus
|
||||||
import no.iktdev.eventi.implementations.EventCoordinator
|
import no.iktdev.eventi.implementations.EventCoordinator
|
||||||
|
import no.iktdev.exfl.using
|
||||||
import no.iktdev.mediaprocessing.coordinator.Coordinator
|
import no.iktdev.mediaprocessing.coordinator.Coordinator
|
||||||
import no.iktdev.mediaprocessing.coordinator.CoordinatorEventListener
|
import no.iktdev.mediaprocessing.coordinator.CoordinatorEventListener
|
||||||
import no.iktdev.mediaprocessing.shared.common.DownloadClient
|
import no.iktdev.mediaprocessing.shared.common.DownloadClient
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.SharedConfig
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.EventsListenerContract
|
import no.iktdev.mediaprocessing.shared.common.contract.EventsListenerContract
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.EventsManagerContract
|
import no.iktdev.mediaprocessing.shared.common.contract.EventsManagerContract
|
||||||
@ -49,24 +51,13 @@ class CoverDownloadTaskListener : CoordinatorEventListener() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val outDir = File(data.outDir)
|
val client = DownloadClient(data.url, SharedConfig.cachedContent, data.outFileBaseName)
|
||||||
.also {
|
|
||||||
if (!it.exists()) {
|
|
||||||
it.mkdirs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!outDir.exists()) {
|
|
||||||
log.error { "Check for output directory for cover storage failed for ${event.metadata.eventId} " }
|
|
||||||
onProduceEvent(failedEventDefault)
|
|
||||||
}
|
|
||||||
|
|
||||||
val client = DownloadClient(data.url, File(data.outDir), data.outFileBaseName)
|
|
||||||
|
|
||||||
val outFile = runBlocking {
|
val outFile = runBlocking {
|
||||||
client.getOutFile()
|
client.getOutFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
val coversInDifferentFormats = outDir.listFiles { it -> it.isFile && it.extension.lowercase() in client.contentTypeToExtension().values } ?: emptyArray()
|
val coversInDifferentFormats = SharedConfig.cachedContent.listFiles { it -> it.isFile && it.extension.lowercase() in client.contentTypeToExtension().values } ?: emptyArray()
|
||||||
|
|
||||||
val result = if (outFile?.exists() == true) {
|
val result = if (outFile?.exists() == true) {
|
||||||
outFile
|
outFile
|
||||||
|
|||||||
@ -86,7 +86,6 @@ class CoverFromMetadataTaskListener: CoordinatorEventListener() {
|
|||||||
data = CoverDetails(
|
data = CoverDetails(
|
||||||
url = coverUrl,
|
url = coverUrl,
|
||||||
outFileBaseName = NameHelper.normalize(coverTitle),
|
outFileBaseName = NameHelper.normalize(coverTitle),
|
||||||
outDir = mediaOutInfo.outDirectory,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,6 @@ class EncodeWorkArgumentsTaskListener: CoordinatorEventListener() {
|
|||||||
val mapper = EncodeWorkArgumentsMapping(
|
val mapper = EncodeWorkArgumentsMapping(
|
||||||
inputFile = inputFile,
|
inputFile = inputFile,
|
||||||
outFileFullName = mediaInfoData.fullName,
|
outFileFullName = mediaInfoData.fullName,
|
||||||
outFileAbsolutePathFile = mediaInfo.data?.outDirectory?.let { File(it) } ?: return,
|
|
||||||
streams = streams,
|
streams = streams,
|
||||||
preference = preference.encodePreference
|
preference = preference.encodePreference
|
||||||
)
|
)
|
||||||
|
|||||||
@ -77,7 +77,6 @@ class ExtractWorkArgumentsTaskListener: CoordinatorEventListener() {
|
|||||||
val mapper = ExtractWorkArgumentsMapping(
|
val mapper = ExtractWorkArgumentsMapping(
|
||||||
inputFile = inputFile,
|
inputFile = inputFile,
|
||||||
outFileFullName = mediaInfoData.fullName,
|
outFileFullName = mediaInfoData.fullName,
|
||||||
outFileAbsolutePathFile = mediaInfo.data?.outDirectory?.let { File(it) } ?: return,
|
|
||||||
streams = streams
|
streams = streams
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -7,12 +7,10 @@ import no.iktdev.eventi.data.EventStatus
|
|||||||
import no.iktdev.exfl.using
|
import no.iktdev.exfl.using
|
||||||
import no.iktdev.mediaprocessing.coordinator.Coordinator
|
import no.iktdev.mediaprocessing.coordinator.Coordinator
|
||||||
import no.iktdev.mediaprocessing.coordinator.CoordinatorEventListener
|
import no.iktdev.mediaprocessing.coordinator.CoordinatorEventListener
|
||||||
import no.iktdev.mediaprocessing.coordinator.utils.log
|
import no.iktdev.mediaprocessing.coordinator.log
|
||||||
import no.iktdev.mediaprocessing.shared.common.SharedConfig
|
import no.iktdev.mediaprocessing.shared.common.SharedConfig
|
||||||
import no.iktdev.mediaprocessing.shared.common.parsing.FileNameDeterminate
|
import no.iktdev.mediaprocessing.shared.common.parsing.FileNameDeterminate
|
||||||
import no.iktdev.mediaprocessing.shared.common.parsing.NameHelper
|
import no.iktdev.mediaprocessing.shared.common.parsing.NameHelper
|
||||||
import no.iktdev.mediaprocessing.shared.common.parsing.Regexes
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.parsing.isCharOnlyUpperCase
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.data.*
|
import no.iktdev.mediaprocessing.shared.common.contract.data.*
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.data.EpisodeInfo
|
import no.iktdev.mediaprocessing.shared.common.contract.data.EpisodeInfo
|
||||||
@ -68,7 +66,6 @@ class MediaOutInformationTaskListener: CoordinatorEventListener() {
|
|||||||
|
|
||||||
val result = if (vi != null) {
|
val result = if (vi != null) {
|
||||||
MediaInfoReceived(
|
MediaInfoReceived(
|
||||||
outDirectory = pm.getOutputDirectory().absolutePath,
|
|
||||||
info = vi
|
info = vi
|
||||||
).let { MediaOutInformationConstructedEvent(
|
).let { MediaOutInformationConstructedEvent(
|
||||||
metadata = event.makeDerivedEventInfo(EventStatus.Success, getProducerName()),
|
metadata = event.makeDerivedEventInfo(EventStatus.Success, getProducerName()),
|
||||||
@ -135,7 +132,6 @@ class MediaOutInformationTaskListener: CoordinatorEventListener() {
|
|||||||
|
|
||||||
val filteredMetaTitles = metaTitles.filter { it.lowercase().contains(baseInfo.title.lowercase()) || NameHelper.normalize(it).lowercase().contains(baseInfo.title.lowercase()) }
|
val filteredMetaTitles = metaTitles.filter { it.lowercase().contains(baseInfo.title.lowercase()) || NameHelper.normalize(it).lowercase().contains(baseInfo.title.lowercase()) }
|
||||||
|
|
||||||
//val viableFileTitles = filteredMetaTitles.filter { !it.isCharOnlyUpperCase() }
|
|
||||||
|
|
||||||
return if (collection == baseInfo.title) {
|
return if (collection == baseInfo.title) {
|
||||||
collection
|
collection
|
||||||
@ -162,10 +158,6 @@ class MediaOutInformationTaskListener: CoordinatorEventListener() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOutputDirectory() = SharedConfig.outgoingContent.using(NameHelper.normalize(getCollection()))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -13,13 +13,11 @@ import java.io.File
|
|||||||
class EncodeWorkArgumentsMapping(
|
class EncodeWorkArgumentsMapping(
|
||||||
val inputFile: String,
|
val inputFile: String,
|
||||||
val outFileFullName: String,
|
val outFileFullName: String,
|
||||||
val outFileAbsolutePathFile: File,
|
|
||||||
val streams: ParsedMediaStreams,
|
val streams: ParsedMediaStreams,
|
||||||
val preference: EncodingPreference
|
val preference: EncodingPreference
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getArguments(): EncodeArgumentData? {
|
fun getArguments(): EncodeArgumentData? {
|
||||||
val outVideoFileAbsolutePath = outFileAbsolutePathFile.using("${outFileFullName}.mp4").absolutePath
|
|
||||||
val vaas = VideoAndAudioSelector(streams, preference)
|
val vaas = VideoAndAudioSelector(streams, preference)
|
||||||
val vArg = vaas.getVideoStream()
|
val vArg = vaas.getVideoStream()
|
||||||
?.let { VideoArguments(it, streams, preference.video).getVideoArguments() }
|
?.let { VideoArguments(it, streams, preference.video).getVideoArguments() }
|
||||||
@ -32,7 +30,7 @@ class EncodeWorkArgumentsMapping(
|
|||||||
} else {
|
} else {
|
||||||
EncodeArgumentData(
|
EncodeArgumentData(
|
||||||
inputFile = inputFile,
|
inputFile = inputFile,
|
||||||
outputFile = outVideoFileAbsolutePath,
|
outputFileName = "${outFileFullName}.mp4",
|
||||||
arguments = vaArgs
|
arguments = vaArgs
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,19 +9,18 @@ import java.io.File
|
|||||||
class ExtractWorkArgumentsMapping(
|
class ExtractWorkArgumentsMapping(
|
||||||
val inputFile: String,
|
val inputFile: String,
|
||||||
val outFileFullName: String,
|
val outFileFullName: String,
|
||||||
val outFileAbsolutePathFile: File,
|
|
||||||
val streams: ParsedMediaStreams
|
val streams: ParsedMediaStreams
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getArguments(): List<ExtractArgumentData> {
|
fun getArguments(): List<ExtractArgumentData> {
|
||||||
val subDir = outFileAbsolutePathFile.using("sub")
|
|
||||||
val sArg = SubtitleArguments(streams.subtitleStream).getSubtitleArguments()
|
val sArg = SubtitleArguments(streams.subtitleStream).getSubtitleArguments()
|
||||||
|
|
||||||
val entries = sArg.map {
|
val entries = sArg.map {
|
||||||
ExtractArgumentData(
|
ExtractArgumentData(
|
||||||
inputFile = inputFile,
|
inputFile = inputFile,
|
||||||
|
language = it.language,
|
||||||
arguments = it.codecParameters + it.optionalParameters + listOf("-map", "0:s:${it.index}"),
|
arguments = it.codecParameters + it.optionalParameters + listOf("-map", "0:s:${it.index}"),
|
||||||
outputFile = subDir.using(it.language, "${outFileFullName}.${it.format}").absolutePath
|
outputFileName = "${outFileFullName}.${it.language}.${it.format}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,129 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.store
|
||||||
|
|
||||||
|
import mu.KotlinLogging
|
||||||
|
import no.iktdev.eventi.database.executeOrException
|
||||||
|
import no.iktdev.eventi.database.withTransaction
|
||||||
|
import no.iktdev.mediaprocessing.coordinator.getStoreDatabase
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.reader.MetadataDto
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.reader.VideoDetails
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.parsing.NameHelper
|
||||||
|
import no.iktdev.streamit.library.db.insertWithSuccess
|
||||||
|
import no.iktdev.streamit.library.db.query.CatalogQuery
|
||||||
|
import no.iktdev.streamit.library.db.query.MovieQuery
|
||||||
|
import no.iktdev.streamit.library.db.query.SerieQuery
|
||||||
|
import no.iktdev.streamit.library.db.tables.catalog
|
||||||
|
import no.iktdev.streamit.library.db.tables.serie
|
||||||
|
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import java.sql.SQLIntegrityConstraintViolationException
|
||||||
|
|
||||||
|
object ContentCatalogStore {
|
||||||
|
val log = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a list of titles and type,
|
||||||
|
* the codes purpose is to find the matching collection in the catalog by title
|
||||||
|
*/
|
||||||
|
fun getCollectionByTitleAndType(type: String, titles: List<String>): String? {
|
||||||
|
return withTransaction(getStoreDatabase()) {
|
||||||
|
catalog.select {
|
||||||
|
(catalog.type eq type) and
|
||||||
|
((catalog.title inList titles) or
|
||||||
|
(catalog.collection inList titles))
|
||||||
|
}.map {
|
||||||
|
it[catalog.collection]
|
||||||
|
}.firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCover(collection: String, type: String): String? {
|
||||||
|
return withTransaction(getStoreDatabase()) {
|
||||||
|
catalog.select {
|
||||||
|
(catalog.collection eq collection) and
|
||||||
|
(catalog.type eq type)
|
||||||
|
}.map { it[catalog.cover] }.firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun storeCatalog(title: String, collection: String, type: String, cover: String?, genres: String?): Int? {
|
||||||
|
withTransaction(getStoreDatabase()) {
|
||||||
|
val existingRow = catalog.select {
|
||||||
|
(catalog.collection eq collection) and
|
||||||
|
(catalog.type eq type)
|
||||||
|
}.firstOrNull()
|
||||||
|
|
||||||
|
if (existingRow == null) {
|
||||||
|
catalog.insertIgnore {
|
||||||
|
it[catalog.title] = title
|
||||||
|
it[catalog.cover] = cover
|
||||||
|
it[catalog.type] = type
|
||||||
|
it[catalog.collection] = collection
|
||||||
|
it[catalog.genres] = genres
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val id = existingRow[catalog.id]
|
||||||
|
val storedTitle = existingRow[catalog.title]
|
||||||
|
val useCover = existingRow[catalog.cover] ?: cover
|
||||||
|
val useGenres = existingRow[catalog.genres] ?: genres
|
||||||
|
|
||||||
|
catalog.update({
|
||||||
|
(catalog.id eq id) and
|
||||||
|
(catalog.collection eq collection)
|
||||||
|
}) {
|
||||||
|
it[catalog.cover] = useCover
|
||||||
|
it[catalog.genres] = useGenres
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getId(title, collection, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun storeMovie(catalogId: Int, videoDetails: VideoDetails) {
|
||||||
|
val iid = MovieQuery(videoDetails.fileName).insertAndGetId() ?: run {
|
||||||
|
log.error { "Movie id was not returned!" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
withTransaction(getStoreDatabase()) {
|
||||||
|
catalog.update({
|
||||||
|
(catalog.id eq catalogId)
|
||||||
|
}) {
|
||||||
|
it[catalog.iid] = iid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun storeSerie(collection: String, videoDetails: VideoDetails) {
|
||||||
|
val serieInfo = videoDetails.serieInfo ?: run {
|
||||||
|
log.error { "serieInfo in videoDetails is null!" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val insert = withTransaction(getStoreDatabase()) {
|
||||||
|
serie.insertIgnore {
|
||||||
|
it[title] = serieInfo.episodeTitle
|
||||||
|
it[episode] = serieInfo.episodeNumber
|
||||||
|
it[season] = serieInfo.seasonNumber
|
||||||
|
it[video] = videoDetails.fileName
|
||||||
|
it[serie.collection] = collection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun storeMedia(title: String, collection: String, type: String, videoDetails: VideoDetails) {
|
||||||
|
val catalogId = getId(title, collection, type) ?: return
|
||||||
|
when (type) {
|
||||||
|
"movie" -> storeMovie(catalogId, videoDetails)
|
||||||
|
"serie" -> storeSerie(collection, videoDetails)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getId(title: String, collection: String, type: String): Int? {
|
||||||
|
return no.iktdev.streamit.library.db.withTransaction {
|
||||||
|
catalog.select { catalog.title eq title }.andWhere {
|
||||||
|
catalog.type eq type
|
||||||
|
}.map { it[catalog.id].value }.firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.store
|
||||||
|
|
||||||
|
import mu.KotlinLogging
|
||||||
|
import no.iktdev.eventi.data.dataAs
|
||||||
|
import no.iktdev.exfl.using
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.SharedConfig
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.data.*
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.moveTo
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.notExist
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class ContentCompletionMover(val collection: String, val events: List<Event>) {
|
||||||
|
val log = KotlinLogging.logger {}
|
||||||
|
val storeFolder = SharedConfig.outgoingContent.using(collection)
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (storeFolder.notExist()) {
|
||||||
|
log.info { "Creating missing folders for path ${storeFolder.absolutePath}" }
|
||||||
|
storeFolder.mkdirs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Pair<OldPath, NewPath> or null if no file found
|
||||||
|
*/
|
||||||
|
fun moveVideo(): Pair<String, String>? {
|
||||||
|
val encodedFile = events.find { it.eventType == Events.EventWorkEncodePerformed }?.dataAs<EncodedData>()?.outputFile?.let {
|
||||||
|
File(it)
|
||||||
|
} ?: return null
|
||||||
|
if (!encodedFile.exists()) {
|
||||||
|
log.error { "Provided file ${encodedFile.absolutePath} does not exist at the given location" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val storeFile = storeFolder.using(encodedFile.name)
|
||||||
|
val result = encodedFile.moveTo(storeFile) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return if (result) Pair(encodedFile.absolutePath, storeFile.absolutePath) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveCover(): Pair<String, String>? {
|
||||||
|
val coverFile = events.find { it.eventType == Events.EventWorkDownloadCoverPerformed }?.
|
||||||
|
az<MediaCoverDownloadedEvent>()?.data?.absoluteFilePath?.let {
|
||||||
|
File(it)
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
if (coverFile.notExist()) {
|
||||||
|
log.error { "Provided file ${coverFile.absolutePath} does not exist at the given location" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val storeFile = storeFolder.using(coverFile.name)
|
||||||
|
val result = coverFile.moveTo(storeFile)
|
||||||
|
return if (result) Pair(coverFile.absolutePath, storeFile.absolutePath) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getMovableSubtitles(): Map<String, List<File>> {
|
||||||
|
val extracted =
|
||||||
|
events.filter { it.eventType == Events.EventWorkExtractPerformed }.mapNotNull { it.dataAs<ExtractedData>() }
|
||||||
|
val converted =
|
||||||
|
events.filter { it.eventType == Events.EventWorkConvertPerformed }.mapNotNull { it.dataAs<ConvertedData>() }
|
||||||
|
|
||||||
|
return extracted.groupBy { it.language }.mapValues { v -> v.value.map { File(it.outputFile) } } +
|
||||||
|
converted.groupBy { it.language }.mapValues { v -> v.value.flatMap { it.outputFiles }.map { File(it) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MovedSubtitle(
|
||||||
|
val language: String,
|
||||||
|
val source: File,
|
||||||
|
val destination: File
|
||||||
|
)
|
||||||
|
|
||||||
|
fun moveSubtitles(): List<MovedSubtitle>? {
|
||||||
|
val subtitleFolder = storeFolder.using("sub")
|
||||||
|
val moved: MutableList<MovedSubtitle> = mutableListOf()
|
||||||
|
|
||||||
|
val subtitles = getMovableSubtitles()
|
||||||
|
if (subtitles.isEmpty() || subtitles.values.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
for ((lang, files) in subtitles) {
|
||||||
|
val languageFolder = subtitleFolder.using(lang).also {
|
||||||
|
if (it.notExist()) {
|
||||||
|
it.mkdirs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (file in files) {
|
||||||
|
val storeFile = languageFolder.using(file.name)
|
||||||
|
val success = file.moveTo(storeFile)
|
||||||
|
if (success) {
|
||||||
|
moved.add(MovedSubtitle(lang, file, storeFile))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return moved
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.store
|
||||||
|
|
||||||
|
import no.iktdev.eventi.database.withTransaction
|
||||||
|
import no.iktdev.mediaprocessing.coordinator.getStoreDatabase
|
||||||
|
import no.iktdev.streamit.library.db.query.GenreQuery
|
||||||
|
|
||||||
|
object ContentGenresStore {
|
||||||
|
fun storeAndGetIds(genres: List<String>): String? {
|
||||||
|
return try {
|
||||||
|
withTransaction(getStoreDatabase()) {
|
||||||
|
val gq = GenreQuery( *genres.toTypedArray() )
|
||||||
|
gq.insertAndGetIds()
|
||||||
|
gq.getIds().joinToString(",")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.store
|
||||||
|
|
||||||
|
import no.iktdev.eventi.database.executeOrException
|
||||||
|
import no.iktdev.eventi.database.withTransaction
|
||||||
|
import no.iktdev.mediaprocessing.coordinator.getStoreDatabase
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.reader.SummaryInfo
|
||||||
|
import no.iktdev.streamit.library.db.query.SummaryQuery
|
||||||
|
|
||||||
|
object ContentMetadataStore {
|
||||||
|
|
||||||
|
fun storeSummary(catalogId: Int, summaryInfo: SummaryInfo) {
|
||||||
|
val result = executeOrException(getStoreDatabase().database) {
|
||||||
|
SummaryQuery(
|
||||||
|
cid = catalogId,
|
||||||
|
language = summaryInfo.language,
|
||||||
|
description = summaryInfo.summary
|
||||||
|
).insert()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.store
|
||||||
|
|
||||||
|
import no.iktdev.eventi.database.executeWithStatus
|
||||||
|
import no.iktdev.mediaprocessing.coordinator.getStoreDatabase
|
||||||
|
import no.iktdev.streamit.library.db.query.SubtitleQuery
|
||||||
|
import no.iktdev.streamit.library.db.tables.subtitle
|
||||||
|
import org.jetbrains.exposed.sql.insert
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object ContentSubtitleStore {
|
||||||
|
|
||||||
|
fun storeSubtitles(collection: String, language: String, destinationFile: File): Boolean {
|
||||||
|
return executeWithStatus (getStoreDatabase()) {
|
||||||
|
subtitle.insert {
|
||||||
|
it[this.associatedWithVideo] = destinationFile.nameWithoutExtension
|
||||||
|
it[this.language] = language
|
||||||
|
it[this.collection] = collection
|
||||||
|
it[this.format] = destinationFile.extension.uppercase()
|
||||||
|
it[this.subtitle] = destinationFile.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.tasksV2.mapping.store
|
||||||
|
|
||||||
|
import no.iktdev.eventi.database.withTransaction
|
||||||
|
import no.iktdev.mediaprocessing.coordinator.getStoreDatabase
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.parsing.NameHelper
|
||||||
|
import no.iktdev.streamit.library.db.tables.titles
|
||||||
|
import org.jetbrains.exposed.sql.insertIgnore
|
||||||
|
import org.jetbrains.exposed.sql.or
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
|
||||||
|
object ContentTitleStore {
|
||||||
|
|
||||||
|
fun store(mainTitle: String, otherTitles: List<String>) {
|
||||||
|
try {
|
||||||
|
withTransaction(getStoreDatabase()) {
|
||||||
|
val titlesToUse = otherTitles + listOf(
|
||||||
|
NameHelper.normalize(mainTitle)
|
||||||
|
).filter { it != mainTitle }
|
||||||
|
|
||||||
|
titlesToUse.forEach { t ->
|
||||||
|
titles.insertIgnore {
|
||||||
|
it[masterTitle] = mainTitle
|
||||||
|
it[alternativeTitle] = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findMasterTitles(titleList: List<String>): List<String> {
|
||||||
|
return withTransaction(getStoreDatabase()) {
|
||||||
|
titles.select {
|
||||||
|
(titles.alternativeTitle inList titleList) or
|
||||||
|
(titles.masterTitle inList titleList)
|
||||||
|
}.map {
|
||||||
|
it[titles.masterTitle]
|
||||||
|
}.distinctBy { it }
|
||||||
|
} ?: emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.tasksV2.validator
|
||||||
|
|
||||||
|
import no.iktdev.eventi.data.dataAs
|
||||||
|
import no.iktdev.eventi.data.isSuccessful
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.data.*
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.dto.StartOperationEvents
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.dto.SubtitleFormats
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates whether all the required work has been created and processed in accordance with expected behaviour and sequence
|
||||||
|
*/
|
||||||
|
object CompletionValidator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether it requires encode or extract or both, and it has created events with args
|
||||||
|
*/
|
||||||
|
fun req1(started: MediaProcessStartEvent, events: List<Event>): Boolean {
|
||||||
|
val encodeFulfilledOrSkipped = if (started.data?.operations?.contains(StartOperationEvents.ENCODE) == true) {
|
||||||
|
events.any { it.eventType == Events.EventMediaParameterEncodeCreated }
|
||||||
|
} else true
|
||||||
|
|
||||||
|
val extractFulfilledOrSkipped = if (started.data?.operations?.contains(StartOperationEvents.EXTRACT) == true) {
|
||||||
|
events.any { it.eventType == Events.EventMediaParameterExtractCreated }
|
||||||
|
} else true
|
||||||
|
|
||||||
|
if (!encodeFulfilledOrSkipped || !extractFulfilledOrSkipped) {
|
||||||
|
return false
|
||||||
|
} else return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether work that was supposed to be created has been created.
|
||||||
|
* Checks if all subtitles that can be processed has been created if convert is set.
|
||||||
|
*/
|
||||||
|
fun req2(operations: List<StartOperationEvents>, events: List<Event>): Boolean {
|
||||||
|
if (StartOperationEvents.ENCODE in operations) {
|
||||||
|
val encodeParamter = events.find { it.eventType == Events.EventMediaParameterEncodeCreated }?.az<EncodeArgumentCreatedEvent>()
|
||||||
|
val encodeWork = events.find { it.eventType == Events.EventWorkEncodeCreated }
|
||||||
|
if (encodeParamter?.isSuccessful() == true && (encodeWork == null))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val extractParamter = events.find { it.eventType == Events.EventMediaParameterExtractCreated }?.az<ExtractArgumentCreatedEvent>()
|
||||||
|
val extractWork = events.filter { it.eventType == Events.EventWorkExtractCreated }
|
||||||
|
if (StartOperationEvents.EXTRACT in operations) {
|
||||||
|
if (extractParamter?.isSuccessful() == true && extractParamter.data?.size != extractWork.size)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StartOperationEvents.CONVERT in operations) {
|
||||||
|
val convertWork = events.filter { it.eventType == Events.EventWorkConvertCreated }
|
||||||
|
|
||||||
|
val supportedSubtitleFormats = SubtitleFormats.entries.map { it.name }
|
||||||
|
val eventsSupportsConvert = extractWork.filter { it.data is ExtractArgumentData }
|
||||||
|
.filter { (it.dataAs<ExtractArgumentData>()?.outputFileName?.let { f -> File(f).extension.uppercase() } in supportedSubtitleFormats) }
|
||||||
|
|
||||||
|
if (convertWork.size != eventsSupportsConvert.size)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether all work that has been created has been completed
|
||||||
|
*/
|
||||||
|
fun req3(operations: List<StartOperationEvents>, events: List<Event>): Boolean {
|
||||||
|
if (StartOperationEvents.ENCODE in operations) {
|
||||||
|
val encodeWork = events.filter { it.eventType == Events.EventWorkEncodeCreated }
|
||||||
|
val encodePerformed = events.filter { it.eventType == Events.EventWorkEncodePerformed }
|
||||||
|
if (encodePerformed.size < encodeWork.size)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StartOperationEvents.EXTRACT in operations) {
|
||||||
|
val extractWork = events.filter { it.eventType == Events.EventWorkExtractCreated }
|
||||||
|
val extractPerformed = events.filter { it.eventType == Events.EventWorkExtractPerformed }
|
||||||
|
if (extractPerformed.size < extractWork.size)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StartOperationEvents.CONVERT in operations) {
|
||||||
|
val convertWork = events.filter { it.eventType == Events.EventWorkConvertCreated }
|
||||||
|
val convertPerformed = events.filter { it.eventType == Events.EventWorkConvertPerformed }
|
||||||
|
if (convertPerformed.size < convertWork.size)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if metadata has cover, if so, 2 events are expected
|
||||||
|
*/
|
||||||
|
fun req4(events: List<Event>): Boolean {
|
||||||
|
val metadata = events.find { it.eventType == Events.EventMediaMetadataSearchPerformed }
|
||||||
|
if (metadata?.isSuccessful() != true) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasCover = metadata.dataAs<pyMetadata>()?.cover != null
|
||||||
|
if (hasCover == false) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events.any { it.eventType == Events.EventMediaReadOutCover } && events.any { it.eventType == Events.EventWorkDownloadCoverPerformed }) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,100 +0,0 @@
|
|||||||
package no.iktdev.mediaprocessing.coordinator.reader
|
|
||||||
/*
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import no.iktdev.mediaprocessing.shared.kafka.core.CoordinatorProducer
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.ProcessType
|
|
||||||
import no.iktdev.mediaprocessing.shared.kafka.dto.events_result.BaseInfoPerformed
|
|
||||||
import no.iktdev.mediaprocessing.shared.kafka.dto.events_result.ProcessStarted
|
|
||||||
import no.iktdev.mediaprocessing.shared.kafka.dto.Status
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
|
||||||
import org.junit.jupiter.api.Named
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest
|
|
||||||
import org.junit.jupiter.params.provider.MethodSource
|
|
||||||
import org.mockito.Mock
|
|
||||||
import org.skyscreamer.jsonassert.JSONAssert
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class BaseInfoFromFileTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private lateinit var testBase: KafkaTestBase
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
lateinit var coordinatorProducer: CoordinatorProducer
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val baseInfoFromFile = BaseInfoFromFile(coordinatorProducer)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testReadFileInfo() {
|
|
||||||
val input = ProcessStarted(
|
|
||||||
Status.COMPLETED, ProcessType.FLOW,
|
|
||||||
File("/var/cache/[POTATO] Kage no Jitsuryokusha ni Naritakute! S2 - 01 [h265].mkv").absolutePath
|
|
||||||
)
|
|
||||||
|
|
||||||
val result = baseInfoFromFile.readFileInfo(input)
|
|
||||||
assertThat(result).isInstanceOf(BaseInfoPerformed::class.java)
|
|
||||||
val asResult = result as BaseInfoPerformed
|
|
||||||
assertThat(result.status).isEqualTo(Status.COMPLETED)
|
|
||||||
assertThat(asResult.title).isEqualTo("Kage no Jitsuryokusha ni Naritakute!")
|
|
||||||
assertThat(asResult.sanitizedName).isEqualTo("Kage no Jitsuryokusha ni Naritakute! S2 - 01")
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@MethodSource("names")
|
|
||||||
fun test(data: TestInfo) {
|
|
||||||
val gson = Gson()
|
|
||||||
val result = baseInfoFromFile.readFileInfo(data.input)
|
|
||||||
JSONAssert.assertEquals(
|
|
||||||
data.expected,
|
|
||||||
gson.toJson(result),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
data class TestInfo(
|
|
||||||
val input: ProcessStarted,
|
|
||||||
val expected: String
|
|
||||||
)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
private fun names(): List<Named<TestInfo>> {
|
|
||||||
return listOf(
|
|
||||||
Named.of(
|
|
||||||
"Potato", TestInfo(
|
|
||||||
ProcessStarted(
|
|
||||||
Status.COMPLETED, ProcessType.FLOW,
|
|
||||||
"E:\\input\\Top Clown Findout.1080p.H264.AAC5.1.mkv"
|
|
||||||
),
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"status": "COMPLETED",
|
|
||||||
"title": "Top Clown Findout",
|
|
||||||
"sanitizedName": "Top Clown Findout"
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Named.of("Filename with UHD wild tag", TestInfo(
|
|
||||||
ProcessStarted(
|
|
||||||
Status.COMPLETED, ProcessType.FLOW,
|
|
||||||
"E:\\input\\Wicked.Potato.Chapter.1.2023.UHD.BluRay.2160p.DDP.7.1.DV.HDR.x265.mp4"
|
|
||||||
),
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"status": "COMPLETED",
|
|
||||||
"title": "Wicked Potato Chapter 1",
|
|
||||||
"sanitizedName": "Wicked Potato Chapter 1"
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}*/
|
|
||||||
@ -20,7 +20,6 @@ class EncodeWorkArgumentsMappingTest {
|
|||||||
val parser = EncodeWorkArgumentsMapping(
|
val parser = EncodeWorkArgumentsMapping(
|
||||||
"potato.mkv",
|
"potato.mkv",
|
||||||
"potato.mp4",
|
"potato.mp4",
|
||||||
File(".\\potato.mp4"),
|
|
||||||
event.az<MediaFileStreamsParsedEvent>()!!.data!!,
|
event.az<MediaFileStreamsParsedEvent>()!!.data!!,
|
||||||
EncodingPreference(VideoPreference(), AudioPreference())
|
EncodingPreference(VideoPreference(), AudioPreference())
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,8 +2,10 @@ package no.iktdev.mediaprocessing.processer.ffmpeg
|
|||||||
|
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import mu.KLogger
|
import mu.KLogger
|
||||||
|
import no.iktdev.exfl.using
|
||||||
import no.iktdev.mediaprocessing.processer.taskManager
|
import no.iktdev.mediaprocessing.processer.taskManager
|
||||||
import no.iktdev.mediaprocessing.shared.common.ClaimableTask
|
import no.iktdev.mediaprocessing.shared.common.ClaimableTask
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.SharedConfig
|
||||||
import no.iktdev.mediaprocessing.shared.common.TaskQueueListener
|
import no.iktdev.mediaprocessing.shared.common.TaskQueueListener
|
||||||
import no.iktdev.mediaprocessing.shared.common.getComputername
|
import no.iktdev.mediaprocessing.shared.common.getComputername
|
||||||
import no.iktdev.mediaprocessing.shared.common.services.TaskService
|
import no.iktdev.mediaprocessing.shared.common.services.TaskService
|
||||||
@ -18,6 +20,10 @@ abstract class FfmpegTaskService: TaskService(), FfmpegListener {
|
|||||||
|
|
||||||
protected var runner: FfmpegRunner? = null
|
protected var runner: FfmpegRunner? = null
|
||||||
|
|
||||||
|
fun getTemporaryStoreFile(fileName: String): File {
|
||||||
|
return SharedConfig.cachedContent.using(fileName)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTaskAvailable(data: ClaimableTask) {
|
override fun onTaskAvailable(data: ClaimableTask) {
|
||||||
if (runner?.isWorking() == true) {
|
if (runner?.isWorking() == true) {
|
||||||
//log.info { "Worker is already running.., will not consume" }
|
//log.info { "Worker is already running.., will not consume" }
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class EncodeService(
|
|||||||
|
|
||||||
fun startEncode(event: Task) {
|
fun startEncode(event: Task) {
|
||||||
val ffwrc = event.data as EncodeArgumentData
|
val ffwrc = event.data as EncodeArgumentData
|
||||||
val outFile = File(ffwrc.outputFile)
|
val outFile = getTemporaryStoreFile(ffwrc.outputFileName)
|
||||||
outFile.parentFile.mkdirs()
|
outFile.parentFile.mkdirs()
|
||||||
if (!logDir.exists()) {
|
if (!logDir.exists()) {
|
||||||
logDir.mkdirs()
|
logDir.mkdirs()
|
||||||
@ -75,7 +75,7 @@ class EncodeService(
|
|||||||
log.info { "Claim successful for ${event.referenceId} encode" }
|
log.info { "Claim successful for ${event.referenceId} encode" }
|
||||||
runner = FfmpegRunner(
|
runner = FfmpegRunner(
|
||||||
inputFile = ffwrc.inputFile,
|
inputFile = ffwrc.inputFile,
|
||||||
outputFile = ffwrc.outputFile,
|
outputFile = outFile.absolutePath,
|
||||||
arguments = ffwrc.arguments,
|
arguments = ffwrc.arguments,
|
||||||
logDir = logDir, listener = this
|
logDir = logDir, listener = this
|
||||||
)
|
)
|
||||||
@ -83,7 +83,7 @@ class EncodeService(
|
|||||||
if (ffwrc.arguments.firstOrNull() != "-y") {
|
if (ffwrc.arguments.firstOrNull() != "-y") {
|
||||||
this.onError(
|
this.onError(
|
||||||
ffwrc.inputFile,
|
ffwrc.inputFile,
|
||||||
"${this::class.java.simpleName} identified the file as already existing, either allow overwrite or delete the offending file: ${ffwrc.outputFile}"
|
"${this::class.java.simpleName} identified the file as already existing, either allow overwrite or delete the offending file: ${outFile.absolutePath}"
|
||||||
)
|
)
|
||||||
// Setting consumed to prevent spamming
|
// Setting consumed to prevent spamming
|
||||||
taskManager.markTaskAsCompleted(event.referenceId, event.eventId, Status.ERROR)
|
taskManager.markTaskAsCompleted(event.referenceId, event.eventId, Status.ERROR)
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import no.iktdev.mediaprocessing.shared.common.limitedWhile
|
|||||||
import no.iktdev.mediaprocessing.shared.common.database.cal.Status
|
import no.iktdev.mediaprocessing.shared.common.database.cal.Status
|
||||||
import no.iktdev.mediaprocessing.shared.common.task.Task
|
import no.iktdev.mediaprocessing.shared.common.task.Task
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.data.ExtractArgumentData
|
import no.iktdev.mediaprocessing.shared.common.contract.data.ExtractArgumentData
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.data.ExtractWorkCreatedEvent
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.data.ExtractWorkPerformedEvent
|
import no.iktdev.mediaprocessing.shared.common.contract.data.ExtractWorkPerformedEvent
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.data.ExtractedData
|
import no.iktdev.mediaprocessing.shared.common.contract.data.ExtractedData
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.dto.ProcesserEventInfo
|
import no.iktdev.mediaprocessing.shared.common.contract.dto.ProcesserEventInfo
|
||||||
@ -60,9 +61,7 @@ class ExtractService(
|
|||||||
|
|
||||||
fun startExtract(event: Task) {
|
fun startExtract(event: Task) {
|
||||||
val ffwrc = event.data as ExtractArgumentData
|
val ffwrc = event.data as ExtractArgumentData
|
||||||
val outFile = File(ffwrc.outputFile).also {
|
val outputFile = getTemporaryStoreFile(ffwrc.outputFileName)
|
||||||
it.parentFile.mkdirs()
|
|
||||||
}
|
|
||||||
if (!logDir.exists()) {
|
if (!logDir.exists()) {
|
||||||
logDir.mkdirs()
|
logDir.mkdirs()
|
||||||
}
|
}
|
||||||
@ -72,16 +71,16 @@ class ExtractService(
|
|||||||
log.info { "Claim successful for ${event.referenceId} extract" }
|
log.info { "Claim successful for ${event.referenceId} extract" }
|
||||||
runner = FfmpegRunner(
|
runner = FfmpegRunner(
|
||||||
inputFile = ffwrc.inputFile,
|
inputFile = ffwrc.inputFile,
|
||||||
outputFile = ffwrc.outputFile,
|
outputFile = outputFile.absolutePath,
|
||||||
arguments = ffwrc.arguments,
|
arguments = ffwrc.arguments,
|
||||||
logDir = logDir,
|
logDir = logDir,
|
||||||
listener = this
|
listener = this
|
||||||
)
|
)
|
||||||
if (outFile.exists()) {
|
if (outputFile.exists()) {
|
||||||
if (ffwrc.arguments.firstOrNull() != "-y") {
|
if (ffwrc.arguments.firstOrNull() != "-y") {
|
||||||
this.onError(
|
this.onError(
|
||||||
ffwrc.inputFile,
|
ffwrc.inputFile,
|
||||||
"${this::class.java.simpleName} identified the file as already existing, either allow overwrite or delete the offending file: ${ffwrc.outputFile}"
|
"${this::class.java.simpleName} identified the file as already existing, either allow overwrite or delete the offending file: ${outputFile.absolutePath}"
|
||||||
)
|
)
|
||||||
// Setting consumed to prevent spamming
|
// Setting consumed to prevent spamming
|
||||||
taskManager.markTaskAsCompleted(event.referenceId, event.eventId, Status.ERROR)
|
taskManager.markTaskAsCompleted(event.referenceId, event.eventId, Status.ERROR)
|
||||||
@ -102,6 +101,8 @@ class ExtractService(
|
|||||||
|
|
||||||
override fun onCompleted(inputFile: String, outputFile: String) {
|
override fun onCompleted(inputFile: String, outputFile: String) {
|
||||||
val task = assignedTask ?: return
|
val task = assignedTask ?: return
|
||||||
|
assert(task.data is ExtractArgumentData) { "Wrong data type found!" }
|
||||||
|
val taskData = task.data as ExtractArgumentData
|
||||||
log.info { "Extract completed for ${task.referenceId}" }
|
log.info { "Extract completed for ${task.referenceId}" }
|
||||||
runBlocking {
|
runBlocking {
|
||||||
var successfulComplete = false
|
var successfulComplete = false
|
||||||
@ -119,6 +120,7 @@ class ExtractService(
|
|||||||
source = getProducerName()
|
source = getProducerName()
|
||||||
),
|
),
|
||||||
data = ExtractedData(
|
data = ExtractedData(
|
||||||
|
taskData.language,
|
||||||
outputFile
|
outputFile
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import java.io.File
|
|||||||
|
|
||||||
object SharedConfig {
|
object SharedConfig {
|
||||||
var incomingContent: File = if (!System.getenv("DIRECTORY_CONTENT_INCOMING").isNullOrBlank()) File(System.getenv("DIRECTORY_CONTENT_INCOMING")) else File("/src/input")
|
var incomingContent: File = if (!System.getenv("DIRECTORY_CONTENT_INCOMING").isNullOrBlank()) File(System.getenv("DIRECTORY_CONTENT_INCOMING")) else File("/src/input")
|
||||||
|
var cachedContent: File = if (!System.getenv("DIRECTORY_CONTENT_CACHE").isNullOrBlank()) File(System.getenv("DIRECTORY_CONTENT_CACHE")) else File("/src/cache")
|
||||||
val outgoingContent: File = if (!System.getenv("DIRECTORY_CONTENT_OUTGOING").isNullOrBlank()) File(System.getenv("DIRECTORY_CONTENT_OUTGOING")) else File("/src/output")
|
val outgoingContent: File = if (!System.getenv("DIRECTORY_CONTENT_OUTGOING").isNullOrBlank()) File(System.getenv("DIRECTORY_CONTENT_OUTGOING")) else File("/src/output")
|
||||||
|
|
||||||
val ffprobe: String = System.getenv("SUPPORTING_EXECUTABLE_FFPROBE") ?: "ffprobe"
|
val ffprobe: String = System.getenv("SUPPORTING_EXECUTABLE_FFPROBE") ?: "ffprobe"
|
||||||
|
|||||||
@ -5,9 +5,14 @@ import mu.KotlinLogging
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.RandomAccessFile
|
import java.io.RandomAccessFile
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
|
import java.util.zip.CRC32
|
||||||
|
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
fun File.notExist(): Boolean {
|
||||||
|
return !this.exists()
|
||||||
|
}
|
||||||
|
|
||||||
fun isFileAvailable(file: File): Boolean {
|
fun isFileAvailable(file: File): Boolean {
|
||||||
if (!file.exists()) return false
|
if (!file.exists()) return false
|
||||||
var stream: RandomAccessFile? = null
|
var stream: RandomAccessFile? = null
|
||||||
@ -60,3 +65,65 @@ fun silentTry(code: () -> Unit) {
|
|||||||
code.invoke()
|
code.invoke()
|
||||||
} catch (_: Exception) {}
|
} catch (_: Exception) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun File.getCRC32(): Long {
|
||||||
|
val crc = CRC32()
|
||||||
|
this.inputStream().use { input ->
|
||||||
|
val buffer = ByteArray(1024)
|
||||||
|
var bytesRead: Int
|
||||||
|
while (input.read(buffer).also { bytesRead = it } != -1) {
|
||||||
|
crc.update(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun File.moveTo(destinationFile: File, onProgress: (Double) -> Unit = {}): Boolean {
|
||||||
|
require(this.exists())
|
||||||
|
require(destinationFile.notExist())
|
||||||
|
val tempDestinationFile = File(destinationFile.parentFile, "${destinationFile.name}.tmp")
|
||||||
|
|
||||||
|
|
||||||
|
val success: Boolean = run {
|
||||||
|
try {
|
||||||
|
val totalBytes = this.length()
|
||||||
|
var copiedBytes = 0L
|
||||||
|
|
||||||
|
this.inputStream().use { input ->
|
||||||
|
tempDestinationFile.outputStream().use { output ->
|
||||||
|
val buffer = ByteArray(1024)
|
||||||
|
var bytesRead: Int
|
||||||
|
while (input.read(buffer).also { bytesRead = it } != -1) {
|
||||||
|
output.write(buffer, 0, bytesRead)
|
||||||
|
copiedBytes += bytesRead
|
||||||
|
onProgress(copiedBytes.toDouble() / totalBytes * 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val sourceHash = this.getCRC32()
|
||||||
|
val tempFileHash = tempDestinationFile.getCRC32()
|
||||||
|
|
||||||
|
if (sourceHash == tempFileHash) {
|
||||||
|
if (!tempDestinationFile.renameTo(destinationFile)) {
|
||||||
|
logger.error { "${tempDestinationFile.name} failed to rename to ${destinationFile.name}" }
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
this.delete()
|
||||||
|
} else {
|
||||||
|
logger.error { "${tempDestinationFile.name} failed integrity check" }
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ data class ConvertWorkCreatedEvent(
|
|||||||
|
|
||||||
data class ConvertData(
|
data class ConvertData(
|
||||||
override val inputFile: String,
|
override val inputFile: String,
|
||||||
|
val language: String,
|
||||||
val outputDirectory: String,
|
val outputDirectory: String,
|
||||||
val outputFileName: String,
|
val outputFileName: String,
|
||||||
val formats: List<SubtitleFormats> = emptyList(),
|
val formats: List<SubtitleFormats> = emptyList(),
|
||||||
|
|||||||
@ -12,5 +12,6 @@ class ConvertWorkPerformed(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class ConvertedData(
|
data class ConvertedData(
|
||||||
|
val language: String,
|
||||||
val outputFiles: List<String>
|
val outputFiles: List<String>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -14,6 +14,6 @@ data class EncodeArgumentCreatedEvent(
|
|||||||
|
|
||||||
data class EncodeArgumentData(
|
data class EncodeArgumentData(
|
||||||
val arguments: List<String>,
|
val arguments: List<String>,
|
||||||
val outputFile: String,
|
val outputFileName: String,
|
||||||
override val inputFile: String
|
override val inputFile: String
|
||||||
): TaskData()
|
): TaskData()
|
||||||
@ -13,6 +13,7 @@ data class ExtractArgumentCreatedEvent(
|
|||||||
|
|
||||||
data class ExtractArgumentData(
|
data class ExtractArgumentData(
|
||||||
val arguments: List<String>,
|
val arguments: List<String>,
|
||||||
val outputFile: String,
|
val language: String,
|
||||||
|
val outputFileName: String,
|
||||||
override val inputFile: String
|
override val inputFile: String
|
||||||
): TaskData()
|
): TaskData()
|
||||||
@ -12,5 +12,6 @@ data class ExtractWorkPerformedEvent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class ExtractedData(
|
data class ExtractedData(
|
||||||
|
val language: String,
|
||||||
val outputFile: String
|
val outputFile: String
|
||||||
)
|
)
|
||||||
@ -12,6 +12,5 @@ data class MediaCoverInfoReceivedEvent(
|
|||||||
|
|
||||||
data class CoverDetails(
|
data class CoverDetails(
|
||||||
val url: String,
|
val url: String,
|
||||||
val outDir: String,
|
|
||||||
val outFileBaseName: String,
|
val outFileBaseName: String,
|
||||||
)
|
)
|
||||||
@ -14,7 +14,6 @@ data class MediaOutInformationConstructedEvent(
|
|||||||
|
|
||||||
data class MediaInfoReceived(
|
data class MediaInfoReceived(
|
||||||
val info: JsonObject,
|
val info: JsonObject,
|
||||||
val outDirectory: String,
|
|
||||||
) {
|
) {
|
||||||
fun toValueObject(): MediaInfo? {
|
fun toValueObject(): MediaInfo? {
|
||||||
val type = info.get("type").asString
|
val type = info.get("type").asString
|
||||||
|
|||||||
@ -7,6 +7,10 @@ import org.springframework.stereotype.Component
|
|||||||
@Component
|
@Component
|
||||||
class MockEventManager(dataSource: MockDataSource = MockDataSource()) : EventsManagerImpl<EventImpl>(dataSource) {
|
class MockEventManager(dataSource: MockDataSource = MockDataSource()) : EventsManagerImpl<EventImpl>(dataSource) {
|
||||||
val events: MutableList<EventImpl> = mutableListOf()
|
val events: MutableList<EventImpl> = mutableListOf()
|
||||||
|
override fun getAvailableReferenceIds(): List<String> {
|
||||||
|
throw RuntimeException("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override fun readAvailableEvents(): List<List<EventImpl>> {
|
override fun readAvailableEvents(): List<List<EventImpl>> {
|
||||||
return listOf(events)
|
return listOf(events)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user