31 Commits

Author SHA1 Message Date
6155ca5c0b [RELEASE] Release v0.2.0 2024-05-12 12:03:31 +02:00
45eb56a6fe [DEV] update relase for island 2024-05-12 11:57:08 +02:00
9e0a834b48 [DEV] update readme 2024-04-15 00:57:00 +02:00
d5f335e1e7 [DEV] add progress callback 2024-04-15 00:56:45 +02:00
df384cc8be [DEV] correct version with some ibrary update 2024-04-13 09:03:05 +02:00
4b545ebbe2 [FIX] update dockerfile 2024-04-07 19:25:07 +02:00
eb3cd1b1fe [DEV] all is operational 2024-04-07 19:13:06 +02:00
95e2e03686 [DEV] all work well 2024-04-07 17:08:43 +02:00
2402fc31ed [DEV] it works without security 2024-04-07 17:05:36 +02:00
763875fbdf {DEV] still work 2024-04-07 09:02:17 +02:00
4ff2b247b4 [DEV] update to basic work 2024-04-06 13:08:12 +02:00
e4246750c7 [DEV] Run but does not realy start 2024-04-05 23:51:48 +02:00
04633240b3 [DEV] find how to fix the error but not Ok with the result 2024-04-03 00:34:47 +02:00
c76a339caf [DEV] update new model with remote library (not work) 2024-03-29 18:39:33 +01:00
8a5758af78 [DEV] remove submodule and correct first init 2024-03-23 07:27:27 +01:00
e05fe70f80 [DEV] ready for deply new model of data UUID 2024-03-19 23:17:05 +01:00
f6f9fa199a [DEV] update new version 2024-03-19 19:17:04 +01:00
a1684f0fc0 [DEV] update new model 2024-03-19 08:37:07 +01:00
cebf7d35fb [DEV] update all the model 2024-03-17 23:45:38 +01:00
5d8dab3742 [DEV] finish base of port but not tested 2024-03-15 07:59:23 +01:00
9a3f28553d [DEV] basic migration of to the new generation interface 2024-03-11 00:07:46 +01:00
48e14212db [DEV] implement partial migration to support new uuid for data and local cover of model 2024-03-04 00:14:08 +01:00
c3e2b7240b [DEV] migrate with succes to angular17 2024-02-26 00:01:37 +01:00
0af1bbfb52 [DEV] correct the backend can not insert trach artist ... fail t in archidata model 2024-02-26 00:01:05 +01:00
619973459a [DEV] continue migration to Angular17 2024-02-23 00:37:47 +01:00
d37ce25621 [DEV] update to angular17 2024-02-15 22:59:35 +01:00
b4157877c3 [DEV] add search in artist and album 2024-01-27 19:34:53 +01:00
883866d5f6 [DEV] update display better 2024-01-27 18:09:29 +01:00
247064e412 [DEV] remove test replace 2024-01-25 23:39:41 +01:00
70c63882e4 [DEV] corrrect the desplay of the player overflow (and some redesign) 2024-01-25 23:37:36 +01:00
9da93a2831 [DEV] update dev tag version 2024-01-19 22:50:09 +01:00
113 changed files with 16233 additions and 25910 deletions

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "front/src/common"]
path = front/src/common
url = ../common_web.git

View File

@@ -1,7 +1,29 @@
#!/bin/bash #!/bin/bash
version_file="../version.txt"
# update new release dependency
cd back cd back
mvn versions:set -DnewVersion=$(cat ../version.txt) # update the Maven version number
mvn versions:set -DnewVersion=$(sed 's/DEV/SNAPSHOT/g' $version_file)
if grep -q "DEV" "$version_file"; then
# update all versions release of dependency
mvn versions:use-latest-releases
# update our manage dependency as snapshoot
mvn versions:use-latest-versions -Dincludes=kangaroo-and-rabbit
else
# update our manage dependency as release (must be done before)
mvn versions:use-latest-releases -Dincludes=kangaroo-and-rabbit
fi
cd - cd -
cd front
if grep -q "DEV" "$version_file"; then
# update all dependency
pnpm install
pnpm run update_packages
else
# in case of release ==> can not do it automatically ...
fi
cd -

View File

@@ -6,7 +6,7 @@
FROM archlinux:base-devel AS builder FROM archlinux:base-devel AS builder
# update system # update system
RUN pacman -Syu --noconfirm && pacman-db-upgrade \ RUN pacman -Syu --noconfirm && pacman-db-upgrade \
&& pacman -S --noconfirm jdk-openjdk maven npm \ && pacman -S --noconfirm jdk-openjdk maven npm pnpm \
&& pacman -Scc --noconfirm && pacman -Scc --noconfirm
ENV PATH /tmp/node_modules/.bin:$PATH ENV PATH /tmp/node_modules/.bin:$PATH
@@ -29,14 +29,15 @@ RUN mvn clean compile assembly:single
###################################################################################### ######################################################################################
FROM builder AS buildFront FROM builder AS buildFront
ADD front/package-lock.json \ RUN echo "@kangaroo-and-rabbit:registry=https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/npm/" > /root/.npmrc
front/package.json \
ADD front/package.json \
front/karma.conf.js \ front/karma.conf.js \
front/protractor.conf.js \ front/protractor.conf.js \
/tmp/ /tmp/
# install and cache app dependencies # install and cache app dependencies
RUN npm install RUN pnpm install
ADD front/e2e \ ADD front/e2e \
front/tsconfig.json \ front/tsconfig.json \

View File

@@ -20,13 +20,18 @@
<dependency> <dependency>
<groupId>kangaroo-and-rabbit</groupId> <groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId> <artifactId>archidata</artifactId>
<version>0.6.0</version> <version>0.7.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId> <artifactId>slf4j-simple</artifactId>
<version>2.0.9</version> <version>2.0.9</version>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.16.1</version>
</dependency>
<!-- <!--
************************************************************ ************************************************************
** TEST dependency ** ** TEST dependency **

View File

@@ -13,6 +13,7 @@ import org.kar.archidata.api.DataResource;
import org.kar.archidata.catcher.ExceptionCatcher; import org.kar.archidata.catcher.ExceptionCatcher;
import org.kar.archidata.catcher.FailExceptionCatcher; import org.kar.archidata.catcher.FailExceptionCatcher;
import org.kar.archidata.catcher.InputExceptionCatcher; import org.kar.archidata.catcher.InputExceptionCatcher;
import org.kar.archidata.catcher.JacksonCatcher;
import org.kar.archidata.catcher.SystemExceptionCatcher; import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.filter.CORSFilter; import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter; import org.kar.archidata.filter.OptionFilter;
@@ -29,6 +30,8 @@ import org.kar.karusic.api.UserResource;
import org.kar.karusic.filter.KarusicAuthenticationFilter; import org.kar.karusic.filter.KarusicAuthenticationFilter;
import org.kar.karusic.migration.Initialization; import org.kar.karusic.migration.Initialization;
import org.kar.karusic.migration.Migration20231126; import org.kar.karusic.migration.Migration20231126;
import org.kar.karusic.migration.Migration20240225;
import org.kar.karusic.migration.Migration20240226;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -54,6 +57,8 @@ public class WebLauncher {
migrationEngine.setInit(new Initialization()); migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version"); WebLauncher.LOGGER.info("Add migration since last version");
migrationEngine.add(new Migration20231126()); migrationEngine.add(new Migration20231126());
migrationEngine.add(new Migration20240225());
migrationEngine.add(new Migration20240226());
WebLauncher.LOGGER.info("Migrate the DB [START]"); WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(GlobalConfiguration.dbConfig); migrationEngine.migrateWaitAdmin(GlobalConfiguration.dbConfig);
WebLauncher.LOGGER.info("Migrate the DB [STOP]"); WebLauncher.LOGGER.info("Migrate the DB [STOP]");
@@ -87,6 +92,7 @@ public class WebLauncher {
// global authentication system // global authentication system
rc.register(KarusicAuthenticationFilter.class); rc.register(KarusicAuthenticationFilter.class);
// register exception catcher // register exception catcher
rc.register(JacksonCatcher.class);
rc.register(InputExceptionCatcher.class); rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class); rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class); rc.register(FailExceptionCatcher.class);

View File

@@ -1,20 +1,44 @@
package org.kar.karusic; package org.kar.karusic;
import java.util.List;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DataFactoryTsApi;
import org.kar.archidata.tools.ConfigBaseVariable; import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.karusic.api.AlbumResource;
import org.kar.karusic.api.ArtistResource;
import org.kar.karusic.api.Front;
import org.kar.karusic.api.GenderResource;
import org.kar.karusic.api.HealthCheck;
import org.kar.karusic.api.PlaylistResource;
import org.kar.karusic.api.TrackResource;
import org.kar.karusic.api.UserResource;
import org.kar.karusic.migration.Initialization;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class WebLauncherLocal extends WebLauncher { public class WebLauncherLocal extends WebLauncher {
final Logger logger = LoggerFactory.getLogger(WebLauncherLocal.class); private static final Logger LOGGER = LoggerFactory.getLogger(WebLauncherLocal.class);
private WebLauncherLocal() {} private WebLauncherLocal() {}
public static void main(final String[] args) throws InterruptedException { public static void main(final String[] args) throws Exception {
DataFactoryTsApi.generatePackage(List.of(
AlbumResource.class,
ArtistResource.class,
Front.class,
GenderResource.class,
HealthCheck.class,
PlaylistResource.class,
UserResource.class,
TrackResource.class,
DataResource.class),
Initialization.CLASSES_BASE, "../front/src/app/back-api/");
final WebLauncherLocal launcher = new WebLauncherLocal(); final WebLauncherLocal launcher = new WebLauncherLocal();
launcher.process(); launcher.process();
launcher.logger.info("end-configure the server & wait finish process:"); launcher.LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join(); Thread.currentThread().join();
launcher.logger.info("STOP the REST server:"); launcher.LOGGER.info("STOP the REST server:");
} }
@Override @Override

View File

@@ -2,14 +2,21 @@ package org.kar.karusic.api;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.tools.DataTools; import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Album; import org.kar.karusic.model.Album;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
@@ -25,24 +32,28 @@ import jakarta.ws.rs.core.Response;
@Path("/album") @Path("/album")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class AlbumResource { public class AlbumResource {
private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class);
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed("USER") @RolesAllowed("USER")
public static Album getWithId(@PathParam("id") final Long id) throws Exception { @Operation(description = "Get a specific Album with his ID")
public static Album get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Album.class, id); return DataAccess.get(Album.class, id);
} }
@GET @GET
@RolesAllowed("USER") @RolesAllowed("USER")
public List<Album> get() throws Exception { @Operation(description = "Get all the available Albums")
public List<Album> gets() throws Exception {
return DataAccess.gets(Album.class); return DataAccess.gets(Album.class);
} }
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Album post(final String jsonRequest) throws Exception { @Operation(description = "Add an album (when all the data already exist)")
public Album post(@AsyncType(Album.class) final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Album.class, jsonRequest); return DataAccess.insertWithJson(Album.class, jsonRequest);
} }
@@ -50,7 +61,8 @@ public class AlbumResource {
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Album put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { @Operation(description = "Update a specific album")
public Album patch(@PathParam("id") final Long id, @AsyncType(Album.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Album.class, id, jsonRequest); DataAccess.updateWithJson(Album.class, id, jsonRequest);
return DataAccess.get(Album.class, id); return DataAccess.get(Album.class, id);
} }
@@ -58,42 +70,48 @@ public class AlbumResource {
@DELETE @DELETE
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception { @Operation(description = "Remove a specific album")
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Album.class, id); DataAccess.delete(Album.class, id);
return Response.ok().build();
} }
@POST @POST
@Path("{id}/add_track/{trackId}") @Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@Operation(description = "Add a Track on a specific album")
public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Album.class, id, "track", trackId); AddOnManyToMany.removeLink(Album.class, id, "track", trackId);
return DataAccess.get(Album.class, id); return DataAccess.get(Album.class, id);
} }
@GET @DELETE
@Path("{id}/rm_track/{trackId}") @Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Operation(description = "Remove a Track on a specific album")
public Album removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { public Album removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Album.class, id, "track", trackId); AddOnManyToMany.removeLink(Album.class, id, "track", trackId);
return DataAccess.get(Album.class, id); return DataAccess.get(Album.class, id);
} }
@POST @POST
@Path("{id}/add_cover") @Path("{id}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@Operation(description = "Add a cover on a specific album")
@AsyncType(Album.class)
@TypeScriptProgress
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) { @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Album.class, id, fileName, fileInputStream, fileMetaData); return DataTools.uploadCover(Album.class, id, fileName, fileInputStream, fileMetaData);
} }
@GET @DELETE
@Path("{id}/rm_cover/{coverId}") @Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { @Operation(description = "Remove a cover on a specific album")
AddOnManyToMany.removeLink(Album.class, id, "cover", coverId); public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
return Response.ok(DataAccess.get(Album.class, id)).build(); AddOnDataJson.removeLink(Album.class, id, "covers", coverId);
return DataAccess.get(Album.class, id);
} }
} }

View File

@@ -2,13 +2,18 @@ package org.kar.karusic.api;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.tools.DataTools; import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Artist; import org.kar.karusic.model.Artist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
@@ -25,24 +30,25 @@ import jakarta.ws.rs.core.Response;
@Path("/artist") @Path("/artist")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class ArtistResource { public class ArtistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class);
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed("USER") @RolesAllowed("USER")
public static Artist getWithId(@PathParam("id") final Long id) throws Exception { public static Artist get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Artist.class, id); return DataAccess.get(Artist.class, id);
} }
@GET @GET
@RolesAllowed("USER") @RolesAllowed("USER")
public List<Artist> get() throws Exception { public List<Artist> gets() throws Exception {
return DataAccess.gets(Artist.class); return DataAccess.gets(Artist.class);
} }
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Artist put(final String jsonRequest) throws Exception { public Artist post(@AsyncType(Artist.class) final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Artist.class, jsonRequest); return DataAccess.insertWithJson(Artist.class, jsonRequest);
} }
@@ -50,7 +56,7 @@ public class ArtistResource {
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Artist put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { public Artist patch(@PathParam("id") final Long id, @AsyncType(Artist.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Artist.class, id, jsonRequest); DataAccess.updateWithJson(Artist.class, id, jsonRequest);
return DataAccess.get(Artist.class, id); return DataAccess.get(Artist.class, id);
} }
@@ -58,25 +64,27 @@ public class ArtistResource {
@DELETE @DELETE
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Artist.class, id); DataAccess.delete(Artist.class, id);
return Response.ok().build();
} }
@POST @POST
@Path("{id}/add_cover") @Path("{id}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@AsyncType(Artist.class)
@TypeScriptProgress
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) { @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Artist.class, id, fileName, fileInputStream, fileMetaData); return DataTools.uploadCover(Artist.class, id, fileName, fileInputStream, fileMetaData);
} }
@GET @DELETE
@Path("{id}/rm_cover/{coverId}") @Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { public Artist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
AddOnManyToMany.removeLink(Artist.class, id, "cover", coverId); LOGGER.error("klmlmkmlkmlklmklmk");
return Response.ok(DataAccess.get(Artist.class, id)).build(); AddOnDataJson.removeLink(Artist.class, id, "covers", coverId);
return DataAccess.get(Artist.class, id);
} }
} }

View File

@@ -2,13 +2,18 @@ package org.kar.karusic.api;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.tools.DataTools; import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Gender; import org.kar.karusic.model.Gender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
@@ -25,24 +30,25 @@ import jakarta.ws.rs.core.Response;
@Path("/gender") @Path("/gender")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class GenderResource { public class GenderResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class);
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed("USER") @RolesAllowed("USER")
public static Gender getWithId(@PathParam("id") final Long id) throws Exception { public static Gender get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Gender.class, id); return DataAccess.get(Gender.class, id);
} }
@GET @GET
@RolesAllowed("USER") @RolesAllowed("USER")
public List<Gender> get() throws Exception { public List<Gender> gets() throws Exception {
return DataAccess.gets(Gender.class); return DataAccess.gets(Gender.class);
} }
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Gender put(final String jsonRequest) throws Exception { public Gender post(@AsyncType(Gender.class) final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Gender.class, jsonRequest); return DataAccess.insertWithJson(Gender.class, jsonRequest);
} }
@@ -50,7 +56,7 @@ public class GenderResource {
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Gender put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { public Gender patch(@PathParam("id") final Long id, @AsyncType(Gender.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Gender.class, id, jsonRequest); DataAccess.updateWithJson(Gender.class, id, jsonRequest);
return DataAccess.get(Gender.class, id); return DataAccess.get(Gender.class, id);
} }
@@ -58,25 +64,26 @@ public class GenderResource {
@DELETE @DELETE
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Gender.class, id); DataAccess.delete(Gender.class, id);
return Response.ok().build();
} }
@POST @POST
@Path("{id}/add_cover") @Path("{id}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@AsyncType(Gender.class)
@TypeScriptProgress
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) { @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Gender.class, id, fileName, fileInputStream, fileMetaData); return DataTools.uploadCover(Gender.class, id, fileName, fileInputStream, fileMetaData);
} }
@GET @DELETE
@Path("{id}/rm_cover/{coverId}") @Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { public Gender removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
AddOnManyToMany.removeLink(Gender.class, id, "cover", coverId); AddOnDataJson.removeLink(Gender.class, id, "covers", coverId);
return Response.ok(DataAccess.get(Gender.class, id)).build(); return DataAccess.get(Gender.class, id);
} }
} }

View File

@@ -2,13 +2,18 @@ package org.kar.karusic.api;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.tools.DataTools; import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Playlist; import org.kar.karusic.model.Playlist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
@@ -25,24 +30,25 @@ import jakarta.ws.rs.core.Response;
@Path("/playlist") @Path("/playlist")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class PlaylistResource { public class PlaylistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistResource.class);
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed("USER") @RolesAllowed("USER")
public static Playlist getWithId(@PathParam("id") final Long id) throws Exception { public static Playlist get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Playlist.class, id); return DataAccess.get(Playlist.class, id);
} }
@GET @GET
@RolesAllowed("USER") @RolesAllowed("USER")
public List<Playlist> get() throws Exception { public List<Playlist> gets() throws Exception {
return DataAccess.gets(Playlist.class); return DataAccess.gets(Playlist.class);
} }
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Playlist put(final String jsonRequest) throws Exception { public Playlist post(@AsyncType(Playlist.class) final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Playlist.class, jsonRequest); return DataAccess.insertWithJson(Playlist.class, jsonRequest);
} }
@@ -50,7 +56,7 @@ public class PlaylistResource {
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Playlist put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { public Playlist patch(@PathParam("id") final Long id, @AsyncType(Playlist.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Playlist.class, id, jsonRequest); DataAccess.updateWithJson(Playlist.class, id, jsonRequest);
return DataAccess.get(Playlist.class, id); return DataAccess.get(Playlist.class, id);
} }
@@ -58,13 +64,12 @@ public class PlaylistResource {
@DELETE @DELETE
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Playlist.class, id); DataAccess.delete(Playlist.class, id);
return Response.ok().build();
} }
@POST @POST
@Path("{id}/add_track/{trackId}") @Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
public Playlist addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { public Playlist addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
@@ -72,8 +77,8 @@ public class PlaylistResource {
return DataAccess.get(Playlist.class, id); return DataAccess.get(Playlist.class, id);
} }
@GET @DELETE
@Path("{id}/rm_track/{trackId}") @Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Playlist removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { public Playlist removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId); AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId);
@@ -81,19 +86,20 @@ public class PlaylistResource {
} }
@POST @POST
@Path("{id}/add_cover") @Path("{id}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@AsyncType(Playlist.class)
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) { @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Playlist.class, id, fileName, fileInputStream, fileMetaData); return DataTools.uploadCover(Playlist.class, id, fileName, fileInputStream, fileMetaData);
} }
@GET @DELETE
@Path("{id}/rm_cover/{coverId}") @Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { public Playlist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
AddOnManyToMany.removeLink(Playlist.class, id, "cover", coverId); AddOnDataJson.removeLink(Playlist.class, id, "covers", coverId);
return Response.ok(DataAccess.get(Playlist.class, id)).build(); return DataAccess.get(Playlist.class, id);
} }
} }

View File

@@ -5,11 +5,15 @@ import java.io.InputStream;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.model.Data; import org.kar.archidata.model.Data;
@@ -18,6 +22,8 @@ import org.kar.karusic.model.Album;
import org.kar.karusic.model.Artist; import org.kar.karusic.model.Artist;
import org.kar.karusic.model.Gender; import org.kar.karusic.model.Gender;
import org.kar.karusic.model.Track; import org.kar.karusic.model.Track;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
@@ -34,24 +40,25 @@ import jakarta.ws.rs.core.Response;
@Path("/track") @Path("/track")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class TrackResource { public class TrackResource {
private static final Logger LOGGER = LoggerFactory.getLogger(TrackResource.class);
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed("USER") @RolesAllowed("USER")
public static Track getWithId(@PathParam("id") final Long id) throws Exception { public static Track get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Track.class, id); return DataAccess.get(Track.class, id);
} }
@GET @GET
@RolesAllowed("USER") @RolesAllowed("USER")
public List<Track> get() throws Exception { public List<Track> gets() throws Exception {
return DataAccess.gets(Track.class); return DataAccess.gets(Track.class);
} }
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Track create(final String jsonRequest) throws Exception { public Track post(@AsyncType(Track.class) final String jsonRequest) throws Exception {
return DataAccess.insertWithJson(Track.class, jsonRequest); return DataAccess.insertWithJson(Track.class, jsonRequest);
} }
@@ -59,7 +66,7 @@ public class TrackResource {
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Track put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { public Track patch(@PathParam("id") final Long id, @AsyncType(Track.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Track.class, id, jsonRequest); DataAccess.updateWithJson(Track.class, id, jsonRequest);
return DataAccess.get(Track.class, id); return DataAccess.get(Track.class, id);
} }
@@ -67,13 +74,12 @@ public class TrackResource {
@DELETE @DELETE
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Track.class, id); DataAccess.delete(Track.class, id);
return Response.ok().build();
} }
@POST @POST
@Path("{id}/add_artist/{artistId}") @Path("{id}/artist/{artistId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
public Track addTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception { public Track addTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
@@ -81,8 +87,8 @@ public class TrackResource {
return DataAccess.get(Track.class, id); return DataAccess.get(Track.class, id);
} }
@GET @DELETE
@Path("{id}/rm_artist/{trackId}") @Path("{id}/artist/{trackId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Track removeTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception { public Track removeTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
AddOnManyToMany.removeLink(Track.class, id, "artist", artistId); AddOnManyToMany.removeLink(Track.class, id, "artist", artistId);
@@ -90,30 +96,43 @@ public class TrackResource {
} }
@POST @POST
@Path("{id}/add_cover") @Path("{id}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@AsyncType(Track.class)
@TypeScriptProgress
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) { @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
return DataTools.uploadCover(Track.class, id, fileName, fileInputStream, fileMetaData); return DataTools.uploadCover(Track.class, id, fileName, fileInputStream, fileMetaData);
} }
@GET @DELETE
@Path("{id}/rm_cover/{coverId}") @Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { public Track removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
AddOnManyToMany.removeLink(Track.class, id, "cover", coverId); AddOnDataJson.removeLink(Track.class, id, "covers", coverId);
return Response.ok(DataAccess.get(Track.class, id)).build(); return DataAccess.get(Track.class, id);
} }
@POST @POST
@Path("/upload/") @Path("upload/")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
public Response uploadFile(@FormDataParam("fileName") String fileName, @FormDataParam("gender") String gender, @FormDataParam("artist") String artist, // Formatter:off
@AsyncType(Track.class)
@TypeScriptProgress
public Response uploadTrack(
@FormDataParam("fileName") String fileName, //
@FormDataParam("gender") String gender, //
@FormDataParam("artist") String artist, //
//@FormDataParam("seriesId") String seriesId, Not used ... //@FormDataParam("seriesId") String seriesId, Not used ...
@FormDataParam("album") String album, @FormDataParam("trackId") String trackId, @FormDataParam("title") String title, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("album") String album, //
@FormDataParam("file") final FormDataContentDisposition fileMetaData) { @AsyncType(Long.class) @FormDataParam("trackId") String trackId, //
@FormDataParam("title") String title, //
@FormDataParam("file") final InputStream fileInputStream, //
@FormDataParam("file") final FormDataContentDisposition fileMetaData //
) {
// Formatter:on
try { try {
// correct input string stream : // correct input string stream :
fileName = DataTools.multipartCorrection(fileName); fileName = DataTools.multipartCorrection(fileName);
@@ -124,16 +143,15 @@ public class TrackResource {
title = DataTools.multipartCorrection(title); title = DataTools.multipartCorrection(title);
//public NodeSmall uploadFile(final FormDataMultiPart form) { //public NodeSmall uploadFile(final FormDataMultiPart form) {
System.out.println("Upload media file: " + fileMetaData); LOGGER.info("Upload media file: " + fileMetaData);
System.out.println(" - fileName: " + fileName); LOGGER.info(" > fileName: " + fileName);
System.out.println(" - gender: " + gender); LOGGER.info(" > gender: " + gender);
System.out.println(" - artist: " + artist); LOGGER.info(" > artist: " + artist);
System.out.println(" - album: " + album); LOGGER.info(" > album: " + album);
System.out.println(" - trackId: " + trackId); LOGGER.info(" > trackId: " + trackId);
System.out.println(" - title: " + title); LOGGER.info(" > title: " + title);
System.out.println(" - fileInputStream: " + fileInputStream); LOGGER.info(" > fileInputStream: " + fileInputStream);
System.out.println(" - fileMetaData: " + fileMetaData); LOGGER.info(" > fileMetaData: " + fileMetaData);
System.out.flush();
/* /*
if (typeId == null) { if (typeId == null) {
return Response.status(406). return Response.status(406).
@@ -147,8 +165,8 @@ public class TrackResource {
final String sha512 = DataTools.saveTemporaryFile(fileInputStream, tmpUID); final String sha512 = DataTools.saveTemporaryFile(fileInputStream, tmpUID);
Data data = DataTools.getWithSha512(sha512); Data data = DataTools.getWithSha512(sha512);
if (data == null) { if (data == null) {
System.out.println("Need to add the data in the BDD ... "); LOGGER.info("Need to add the data in the BDD ... ");
System.out.flush();
try { try {
data = DataTools.createNewData(tmpUID, fileName, sha512); data = DataTools.createNewData(tmpUID, fileName, sha512);
} catch (final IOException ex) { } catch (final IOException ex) {
@@ -161,16 +179,14 @@ public class TrackResource {
return Response.notModified("Error in SQL insertion ...").build(); return Response.notModified("Error in SQL insertion ...").build();
} }
} else if (data.deleted) { } else if (data.deleted) {
System.out.println("Data already exist but deleted"); LOGGER.info("Data already exist but deleted");
System.out.flush();
DataTools.undelete(data.id); DataTools.undelete(data.id);
data.deleted = false; data.deleted = false;
} else { } else {
System.out.println("Data already exist ... all good"); LOGGER.info("Data already exist ... all good");
System.out.flush();
} }
// Fist step: retrieve all the Id of each parents:... // Fist step: retrieve all the Id of each parents:...
System.out.println("Find typeNode"); LOGGER.info("Find typeNode");
Gender genderElem = null; Gender genderElem = null;
if (gender != null) { if (gender != null) {
genderElem = DataAccess.getWhere(Gender.class, new Condition(new QueryCondition("name", "=", gender))); genderElem = DataAccess.getWhere(Gender.class, new Condition(new QueryCondition("name", "=", gender)));
@@ -185,18 +201,20 @@ public class TrackResource {
// DataTools.removeTemporaryFile(tmpUID); // DataTools.removeTemporaryFile(tmpUID);
// return Response.notModified("TypeId does not exist ...").build(); // return Response.notModified("TypeId does not exist ...").build();
// } // }
System.out.println(" ==> " + genderElem); LOGGER.info(" ==> genderElem={}", genderElem);
Artist artistElem = null; Artist artistElem = null;
if (artist != null) { if (artist != null) {
LOGGER.info(" Try to find Artist: '{}'", artist);
artistElem = DataAccess.getWhere(Artist.class, new Condition(new QueryCondition("name", "=", artist))); artistElem = DataAccess.getWhere(Artist.class, new Condition(new QueryCondition("name", "=", artist)));
if (artistElem == null) { if (artistElem == null) {
LOGGER.info(" ** Create a new one...");
artistElem = new Artist(); artistElem = new Artist();
artistElem.name = artist; artistElem.name = artist;
artistElem = DataAccess.insert(artistElem); artistElem = DataAccess.insert(artistElem);
} }
} }
System.out.println(" ==> " + artistElem); LOGGER.info(" ==> artistElem={}", artistElem);
Album albumElem = null; Album albumElem = null;
if (album != null) { if (album != null) {
@@ -207,9 +225,9 @@ public class TrackResource {
albumElem = DataAccess.insert(albumElem); albumElem = DataAccess.insert(albumElem);
} }
} }
System.out.println(" ==> " + album); LOGGER.info(" ==> " + album);
System.out.println("add media"); LOGGER.info("add media");
Track trackElem = new Track(); Track trackElem = new Track();
trackElem.name = title; trackElem.name = title;
@@ -217,7 +235,7 @@ public class TrackResource {
trackElem.albumId = albumElem != null ? albumElem.id : null; trackElem.albumId = albumElem != null ? albumElem.id : null;
trackElem.genderId = genderElem != null ? genderElem.id : null; trackElem.genderId = genderElem != null ? genderElem.id : null;
trackElem.dataId = data.id; trackElem.dataId = data.id;
// Now list of artis has an internal management: // Now list of artist has an internal management:
if (artistElem != null) { if (artistElem != null) {
trackElem.artists = new ArrayList<>(); trackElem.artists = new ArrayList<>();
trackElem.artists.add(artistElem.id); trackElem.artists.add(artistElem.id);
@@ -231,7 +249,7 @@ public class TrackResource {
*/ */
return Response.ok(trackElem).build(); return Response.ok(trackElem).build();
} catch (final Exception ex) { } catch (final Exception ex) {
System.out.println("Catch an unexpected error ... " + ex.getMessage()); LOGGER.info("Catch an unexpected error ... {}", ex.getMessage());
ex.printStackTrace(); ex.printStackTrace();
return Response.status(417).entity("Back-end error : " + ex.getMessage()).type("text/plain").build(); return Response.status(417).entity("Back-end error : " + ex.getMessage()).type("text/plain").build();
} }

View File

@@ -22,7 +22,7 @@ import jakarta.ws.rs.core.SecurityContext;
@Path("/users") @Path("/users")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public class UserResource { public class UserResource {
final Logger logger = LoggerFactory.getLogger(UserResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(UserResource.class);
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class UserOut { public class UserOut {
@@ -41,8 +41,8 @@ public class UserResource {
// curl http://localhost:9993/api/users // curl http://localhost:9993/api/users
@GET @GET
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public List<UserKarusic> getUsers() { public List<UserKarusic> gets() {
System.out.println("getUsers"); LOGGER.info("getUsers");
try { try {
return DataAccess.gets(UserKarusic.class); return DataAccess.gets(UserKarusic.class);
} catch (final Exception e) { } catch (final Exception e) {
@@ -56,12 +56,12 @@ public class UserResource {
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public UserKarusic getUsers(@Context final SecurityContext sc, @PathParam("id") final long userId) { public UserKarusic get(@Context final SecurityContext sc, @PathParam("id") final long userId) {
System.out.println("getUser " + userId); LOGGER.info("getUser {}", userId);
final GenericContext gc = (GenericContext) sc.getUserPrincipal(); final GenericContext gc = (GenericContext) sc.getUserPrincipal();
System.out.println("==================================================="); LOGGER.info("===================================================");
System.out.println("== USER ? " + gc.userByToken.name); LOGGER.info("== USER {} ", gc.userByToken.name);
System.out.println("==================================================="); LOGGER.info("===================================================");
try { try {
return DataAccess.get(UserKarusic.class, userId); return DataAccess.get(UserKarusic.class, userId);
} catch (final Exception e) { } catch (final Exception e) {
@@ -75,9 +75,9 @@ public class UserResource {
@Path("me") @Path("me")
@RolesAllowed("USER") @RolesAllowed("USER")
public UserOut getMe(@Context final SecurityContext sc) { public UserOut getMe(@Context final SecurityContext sc) {
this.logger.debug("getMe()"); LOGGER.debug("getMe()");
final GenericContext gc = (GenericContext) sc.getUserPrincipal(); final GenericContext gc = (GenericContext) sc.getUserPrincipal();
this.logger.debug("== USER ? {}", gc.userByToken); LOGGER.debug("== USER ? {}", gc.userByToken);
return new UserOut(gc.userByToken.id, gc.userByToken.name); return new UserOut(gc.userByToken.id, gc.userByToken.name);
} }
} }

View File

@@ -1,5 +1,7 @@
package org.kar.karusic.migration; package org.kar.karusic.migration;
import java.util.List;
import org.kar.archidata.migration.MigrationSqlStep; import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.archidata.model.Data; import org.kar.archidata.model.Data;
import org.kar.archidata.model.User; import org.kar.archidata.model.User;
@@ -12,6 +14,7 @@ import org.kar.karusic.model.Track;
public class Initialization extends MigrationSqlStep { public class Initialization extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1; public static final int KARSO_INITIALISATION_ID = 1;
public static final List<Class<?>> CLASSES_BASE = List.of(Album.class,Artist.class,Data.class,Gender.class,Playlist.class,Track.class,User.class);
@Override @Override
public String getName() { public String getName() {
@@ -24,13 +27,9 @@ public class Initialization extends MigrationSqlStep {
@Override @Override
public void generateStep() throws Exception { public void generateStep() throws Exception {
addClass(Album.class); for (final Class<?> elem : CLASSES_BASE) {
addClass(Artist.class); addClass(elem);
addClass(Data.class); }
addClass(Gender.class);
addClass(Playlist.class);
addClass(Track.class);
addClass(User.class);
addAction(""" addAction("""
INSERT INTO `gender` (`id`, `name`, `description`) VALUES INSERT INTO `gender` (`id`, `name`, `description`) VALUES
@@ -68,9 +67,6 @@ public class Initialization extends MigrationSqlStep {
addAction(""" addAction("""
ALTER TABLE `artist` AUTO_INCREMENT = 1000; ALTER TABLE `artist` AUTO_INCREMENT = 1000;
""", "mysql"); """, "mysql");
addAction("""
ALTER TABLE `data` AUTO_INCREMENT = 1000;
""", "mysql");
addAction(""" addAction("""
ALTER TABLE `gender` AUTO_INCREMENT = 1000; ALTER TABLE `gender` AUTO_INCREMENT = 1000;
""", "mysql"); """, "mysql");

View File

@@ -0,0 +1,26 @@
package org.kar.karusic.migration;
import org.kar.archidata.migration.MigrationSqlStep;
public class Migration20240225 extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2024-02-25: change model of thrack to use real json";
}
public Migration20240225() {
}
@Override
public void generateStep() throws Exception {
// update migration update (last one)
addAction("""
UPDATE `track` SET artists = CONCAT('[', artists, ']') WHERE artists IS NOT NULL
""");
}
}

View File

@@ -0,0 +1,135 @@
package org.kar.karusic.migration;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.model.LinkTable;
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.archidata.tools.UuidUtils;
import org.kar.karusic.migration.model.CoverConversion;
import org.kar.karusic.migration.model.MediaConversion;
import org.kar.karusic.migration.model.UUIDConversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20240226 extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20240226.class);
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2024-02-26: convert base with UUID";
}
public Migration20240226() {
}
@Override
public void generateStep() throws Exception {
addAction("""
ALTER TABLE `data` ADD `uuid` binary(16) AFTER `id`;
""");
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
for (final UUIDConversion elem: datas) {
elem.uuid = UuidUtils.nextUUID();
}
for (final UUIDConversion elem: datas) {
DataAccess.update(elem, elem.id, List.of("uuid"), new OverrideTableName("data"));
}
});
addAction("""
ALTER TABLE `data` CHANGE `uuid` `uuid` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
""");
final List<String> tableToTransform = List.of("album", "artist", "gender", "playlist", "track", "user");
for (final String tableName : tableToTransform ) {
addAction("ALTER TABLE `" + tableName + "` ADD `covers` text NULL;");
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
final List<CoverConversion> medias = DataAccess.gets(CoverConversion.class, new AccessDeletedItems(), new OverrideTableName(tableName));
final List<LinkTable> links = DataAccess.gets(LinkTable.class, new OverrideTableName(tableName + "_link_cover"));
LOGGER.info("Get somes data: {} {} {}", datas.size(), medias.size(), links.size());
for (final CoverConversion media: medias) {
final List<UUID> values = new ArrayList<>();
for (final LinkTable link: links) {
if (link.object1Id.equals(media.id)) {
for (final UUIDConversion data: datas) {
if (data.id.equals(link.object2Id)) {
values.add(data.uuid);
break;
}
}
break;
}
}
if (values.size() != 0) {
media.covers = values;
LOGGER.info(" update: {} => {}", media.id, media.covers);
DataAccess.update(media, media.id, List.of("covers"), new OverrideTableName(tableName));
}
}
});
addAction("DROP TABLE `" + tableName + "_link_cover`;");
}
addAction("""
ALTER TABLE `track` ADD `dataUUID` binary(16) AFTER dataId;
""");
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
final List<MediaConversion> medias = DataAccess.gets(MediaConversion.class, new AccessDeletedItems(), new OverrideTableName("track"));
for (final MediaConversion media: medias) {
for (final UUIDConversion data: datas) {
if (data.id.equals(media.dataId)) {
media.dataUUID = data.uuid;
DataAccess.update(media, media.id, List.of("dataUUID"), new OverrideTableName("track"));
break;
}
}
}
});
addAction("""
DROP TABLE `playlist`;
""");
addAction("""
DROP TABLE `playlist_link_track`;
""");
addAction("""
ALTER TABLE `track` DROP `dataId`;
""");
addAction("""
ALTER TABLE `track` CHANGE `dataUUID` `dataId` binary(16) NOT NULL;
""");
// Move the files...
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
for (final UUIDConversion data: datas) {
final String origin = DataResource.getFileDataOld(data.id);
final String destination = DataResource.getFileData(data.uuid);
LOGGER.info("move file = {}", origin);
LOGGER.info(" ==> {}", destination);
Files.move(Paths.get(origin), Paths.get(destination), StandardCopyOption.ATOMIC_MOVE);
}
});
addAction("""
ALTER TABLE `data` DROP `id`;
""");
addAction("""
ALTER TABLE `data` CHANGE `uuid` `id` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
""");
addAction("""
ALTER TABLE `data` ADD PRIMARY KEY `id` (`id`);
""");
}
}

View File

@@ -0,0 +1,15 @@
package org.kar.karusic.migration.model;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import jakarta.persistence.Id;
public class CoverConversion {
@Id
public Long id = null;
@DataJson
public List<UUID> covers = null;
}

View File

@@ -0,0 +1,12 @@
package org.kar.karusic.migration.model;
import java.util.UUID;
import jakarta.persistence.Id;
public class MediaConversion {
@Id
public Long id = null;
public Long dataId = null;
public UUID dataUUID = null;
}

View File

@@ -0,0 +1,11 @@
package org.kar.karusic.migration.model;
import java.util.UUID;
import jakarta.persistence.Id;
public class UUIDConversion {
@Id
public Long id = null;
public UUID uuid = null;
}

View File

@@ -1,55 +0,0 @@
package org.kar.karusic.model;
/*
CREATE TABLE `data` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`sha512` varchar(129) COLLATE 'utf8_general_ci' NOT NULL,
`mime_type` varchar(128) COLLATE 'utf8_general_ci' NOT NULL,
`size` bigint,
`original_name` TEXT
) AUTO_INCREMENT=64;
*/
import java.sql.ResultSet;
import java.sql.SQLException;
public class DataSmall {
public Long id;
public String sha512;
public String mimeType;
public Long size;
public DataSmall() {
}
public DataSmall(ResultSet rs) {
int iii = 1;
try {
this.id = rs.getLong(iii++);
this.sha512 = rs.getString(iii++);
this.mimeType = rs.getString(iii++);
this.size = rs.getLong(iii++);
} catch (SQLException ex) {
ex.printStackTrace();
}
}
public String getTableSql() {
return """
DROP TABLE IF EXISTS `data`;
CREATE TABLE `data` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'table ID',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
`create_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Time the element has been created',
`modify_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Time the element has been update',
`sha512` varchar(129) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL,
`mime_type` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL,
`size` bigint DEFAULT NULL,
`original_name` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
""";
}
}

View File

@@ -1,104 +0,0 @@
package org.kar.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERSE", "SERIES", "SEASON") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MediaSmall {
public class MediaStreamProperty {
public Long id;
public Long timeSecond;
public Long width;
public Long height;
public Map<String, Long> videos = new HashMap<>();
public Map<String, Long> audios = new HashMap<>();
public Map<String, Long> subtitles = new HashMap<>();
}
public Long id;
public String name;
public String description;
public Long dataId;
public Long typeId;
public Long universeId;
public Long seriesId;
public Long seasonId;
public Integer episode;
public Integer date;
public Integer time;
public String ageLimit;
public List<Long> covers = null;
public MediaStreamProperty media;
public MediaSmall(ResultSet rs) {
int iii = 1;
try {
this.id = rs.getLong(iii++);
this.name = rs.getString(iii++);
this.description = rs.getString(iii++);
this.dataId = rs.getLong(iii++);
if (rs.wasNull()) {
this.dataId = null;
}
this.typeId = rs.getLong(iii++);
if (rs.wasNull()) {
this.typeId = null;
}
this.universeId = rs.getLong(iii++);
if (rs.wasNull()) {
this.universeId = null;
}
this.seriesId = rs.getLong(iii++);
if (rs.wasNull()) {
this.seriesId = null;
}
this.seasonId = rs.getLong(iii++);
if (rs.wasNull()) {
this.seasonId = null;
}
this.episode = rs.getInt(iii++);
if (rs.wasNull()) {
this.episode = null;
}
this.date = rs.getInt(iii++);
if (rs.wasNull()) {
this.date = null;
}
this.time = rs.getInt(iii++);
if (rs.wasNull()) {
this.time = null;
}
this.ageLimit = rs.getString(iii++);
String coversString = rs.getString(iii++);
if (!rs.wasNull()) {
covers = new ArrayList<>();
String[] elements = coversString.split("-");
for (String elem : elements) {
Long tmp = Long.parseLong(elem);
covers.add(tmp);
}
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}

View File

@@ -13,15 +13,16 @@ CREATE TABLE `node` (
*/ */
import java.util.List; import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.Data; import org.kar.archidata.model.Data;
import org.kar.archidata.model.GenericDataSoftDelete; import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class NodeSmall extends GenericDataSoftDelete { public class NodeSmall extends GenericDataSoftDelete {
@@ -29,6 +30,7 @@ public class NodeSmall extends GenericDataSoftDelete {
public String name = null; public String name = null;
@Column(length = 0) @Column(length = 0)
public String description = null; public String description = null;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Data.class) @Schema(description = "List of Id of the specific covers")
public List<Long> covers = null; @DataJson(targetEntity = Data.class)
public List<UUID> covers = null;
} }

View File

@@ -13,9 +13,10 @@ CREATE TABLE `node` (
*/ */
import java.util.List; import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataIfNotExists; import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.addOn.SQLTableExternalForeinKeyAsList; import org.kar.archidata.annotation.DataJson;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
@@ -29,9 +30,9 @@ public class Track extends NodeSmall {
public Long genderId = null; public Long genderId = null;
public Long albumId = null; public Long albumId = null;
public Long track = null; public Long track = null;
public Long dataId = null; public UUID dataId = null;
//@ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class) //@ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
@SQLTableExternalForeinKeyAsList @DataJson
@Column(length = 0) @Column(length = 0)
public List<Long> artists = null; public List<Long> artists = null;

View File

@@ -15,9 +15,7 @@ WORKDIR /application/
RUN npm install RUN npm install
ADD e2e /application/e2e ADD e2e /application/e2e
ADD tsconfig.json /application/ ADD tsconfig.json tslint.json angular.json ./
ADD tslint.json /application/
ADD angular.json /application/
ADD src /application/src ADD src /application/src
# generate build # generate build

View File

@@ -2,7 +2,6 @@
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"newProjectRoot": "projects", "newProjectRoot": "projects",
"defaultProject" : "karusic",
"projects": { "projects": {
"karusic": { "karusic": {
"root": "", "root": "",
@@ -16,9 +15,21 @@
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json", "tsConfig": "src/tsconfig.app.json",
"polyfills" : "src/polyfills.ts", "preserveSymlinks": true,
"assets" : [ "src/assets", "src/favicon.ico" ], "polyfills": [
"styles" : [ "src/styles.less", "src/generic_page.less", "src/theme.color.blue.less", "src/theme.checkbox.less", "src/theme.modal.less" ], "zone.js"
],
"assets": [
"src/assets",
"src/favicon.ico"
],
"styles": [
"src/styles.less",
"src/generic_page.less",
"src/theme.color.blue.less",
"src/theme.checkbox.less",
"src/theme.modal.less"
],
"scripts": [] "scripts": []
}, },
"configurations": { "configurations": {
@@ -31,41 +42,48 @@
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false, "vendorChunk": false,
"buildOptimizer": true, "buildOptimizer": true,
"fileReplacements" : [ { "fileReplacements": [
{
"replace": "src/environments/environment.ts", "replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts" "with": "src/environments/environment.prod.ts"
} ] }
]
}, },
"develop": { "develop": {
"optimization": false, "optimization": false,
"outputHashing": "none", "outputHashing": "none",
"sourceMap" : true,
"namedChunks": true, "namedChunks": true,
"aot" : true, "aot": false,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": true, "vendorChunk": true,
"buildOptimizer" : false "buildOptimizer": false,
"sourceMap": {
"scripts": true,
"styles": true,
"hidden": false,
"vendor": true
}
} }
} }
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"options": { "options": {
"browserTarget" : "karusic:build" "buildTarget": "karusic:build"
}, },
"configurations": { "configurations": {
"production": { "production": {
"browserTarget" : "karusic:build:production" "buildTarget": "karusic:build:production"
}, },
"develop": { "develop": {
"browserTarget" : "karusic:build:develop" "buildTarget": "karusic:build:develop"
} }
} }
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"browserTarget" : "karusic:build" "buildTarget": "karusic:build"
} }
}, },
"test": { "test": {
@@ -73,11 +91,22 @@
"options": { "options": {
"main": "src/test.ts", "main": "src/test.ts",
"karmaConfig": "./karma.conf.js", "karmaConfig": "./karma.conf.js",
"polyfills" : "src/polyfills.ts", "polyfills": [
"zone.js"
],
"tsConfig": "src/tsconfig.spec.json", "tsConfig": "src/tsconfig.spec.json",
"scripts": [], "scripts": [],
"styles" : [ "src/styles.less", "src/generic_page.less", "src/theme.color.blue.less", "src/theme.checkbox.less", "src/theme.modal.less" ], "styles": [
"assets" : [ "src/assets", "src/favicon.ico" ] "src/styles.less",
"src/generic_page.less",
"src/theme.color.blue.less",
"src/theme.checkbox.less",
"src/theme.modal.less"
],
"assets": [
"src/assets",
"src/favicon.ico"
]
} }
}, },
"lint": { "lint": {
@@ -94,8 +123,13 @@
"TTTTTTlint": { "TTTTTTlint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-devkit/build-angular:tslint",
"options": { "options": {
"tsConfig" : [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ], "tsConfig": [
"exclude" : [ "**/node_modules/**" ] "src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
} }
} }
} }
@@ -115,8 +149,12 @@
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-devkit/build-angular:tslint",
"options": { "options": {
"tsConfig" : [ "e2e/tsconfig.e2e.json" ], "tsConfig": [
"exclude" : [ "**/node_modules/**" ] "e2e/tsconfig.e2e.json"
],
"exclude": [
"**/node_modules/**"
]
} }
} }
} }

21733
front/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +1,49 @@
{ {
"name": "karusic", "name": "karusic",
"version": "0.0.0", "version": "0.0.0",
"license": "MIT", "license": "MPL-2",
"scripts": { "scripts": {
"all": "npm run build && npm run test", "all": "npm run build && pnpm run test",
"ng": "ng", "ng": "ng",
"start": "ng serve --configuration=develop --watch --port 4203", "dev": "ng serve --configuration=develop --watch --port 4203",
"build": "ng build --prod", "build": "ng build --prod",
"test": "ng test", "test": "ng test",
"lint": "ng lint", "lint": "ng lint",
"e2e": "ng e2e" "style": "prettier --write .",
"e2e": "ng e2e",
"update_packages": "ncu --upgrade",
"install_dependency": "pnpm install --force",
"link_kar_cw": "pnpm link ../../kar-cw/dist/kar-cw/",
"unlink_kar_cw": "pnpm unlink ../../kar-cw/dist/kar-cw/"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^14.2.10", "@angular/animations": "^17.3.4",
"@angular/cdk": "^14.2.7", "@angular/cdk": "^17.3.4",
"@angular/common": "^14.2.10", "@angular/common": "^17.3.4",
"@angular/compiler": "^14.2.10", "@angular/compiler": "^17.3.4",
"@angular/core": "^14.2.10", "@angular/core": "^17.3.4",
"@angular/forms": "^14.2.10", "@angular/forms": "^17.3.4",
"@angular/material": "^14.2.7", "@angular/material": "^17.3.4",
"@angular/platform-browser": "^14.2.10", "@angular/platform-browser": "^17.3.4",
"@angular/platform-browser-dynamic": "^14.2.10", "@angular/platform-browser-dynamic": "^17.3.4",
"@angular/router": "^14.2.10", "@angular/router": "^17.3.4",
"rxjs": "^7.5.7", "rxjs": "^7.8.1",
"zone.js": "^0.12.0" "zone.js": "^0.14.4",
"zod": "3.22.4",
"@kangaroo-and-rabbit/kar-cw": "^0.2.0"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^14.2.9", "@angular-devkit/build-angular": "^17.3.4",
"@angular-eslint/builder": "14.2.0", "@angular-eslint/builder": "17.3.0",
"@angular-eslint/eslint-plugin": "14.2.0", "@angular-eslint/eslint-plugin": "17.3.0",
"@angular-eslint/eslint-plugin-template": "14.2.0", "@angular-eslint/eslint-plugin-template": "17.3.0",
"@angular-eslint/schematics": "14.2.0", "@angular-eslint/schematics": "17.3.0",
"@angular-eslint/template-parser": "14.2.0", "@angular-eslint/template-parser": "17.3.0",
"@angular/cli": "^14.2.9", "@angular/cli": "^17.3.4",
"@angular/compiler-cli": "^14.2.10", "@angular/compiler-cli": "^17.3.4",
"@angular/language-service": "^14.2.10" "@angular/language-service": "^17.3.4",
"npm-check-updates": "^16.14.18",
"tslib": "^2.6.2"
} }
} }

9705
front/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,11 +6,12 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; // CLI imports router import { Routes, RouterModule } from '@angular/router'; // CLI imports router
import { ForbiddenScene, HomeOutScene, NotFound404Scene, SsoScene } from 'common/scene';
import { OnlyAdminGuard, OnlyUnregisteredGuardHome, OnlyUsersGuard, OnlyUsersGuardHome } from 'common/service';
import { HelpScene, HomeScene, AlbumEditScene, AlbumsScene, ArtistEditScene, ArtistScene, SettingsScene, import {
GenderScene, PlaylistScene, TrackEditScene, TrackScene, UploadScene, ArtistsScene, ArtistAlbumScene, AlbumScene } from './scene'; HelpScene, HomeScene, AlbumEditScene, AlbumsScene, ArtistEditScene, ArtistScene, SettingsScene,
GenderScene, PlaylistScene, TrackEditScene, TrackScene, UploadScene, ArtistsScene, ArtistAlbumScene, AlbumScene
} from './scene';
import { ForbiddenScene, OnlyUsersGuardHome, HomeOutScene, OnlyUnregisteredGuardHome, SsoScene, OnlyAdminGuard, OnlyUsersGuard, NotFound404Scene } from '@kangaroo-and-rabbit/kar-cw';
// import { HelpComponent } from './help/help.component'; // import { HelpComponent } from './help/help.component';
@@ -65,7 +66,7 @@ const routes: Routes = [
component: GenderScene, component: GenderScene,
canActivate: [OnlyUsersGuard], canActivate: [OnlyUsersGuard],
}, },
// display all (artist | album | traks) // display all (artist | album | tracks)
{ {
path: 'gender/:genderId', path: 'gender/:genderId',
component: GenderScene, component: GenderScene,
@@ -107,16 +108,16 @@ const routes: Routes = [
component: ArtistScene, component: ArtistScene,
canActivate: [OnlyUsersGuard], canActivate: [OnlyUsersGuard],
}, },
{
path: 'artist/:artistId/edit',
component: ArtistEditScene,
canActivate: [OnlyAdminGuard],
},
{ {
path: 'artist/:artistId/:albumId', path: 'artist/:artistId/:albumId',
component: ArtistAlbumScene, component: ArtistAlbumScene,
canActivate: [OnlyUsersGuard], canActivate: [OnlyUsersGuard],
}, },
{
path: 'artist-edit/:artistId',
component: ArtistEditScene,
canActivate: [OnlyAdminGuard],
},
// ------------------------------------ // ------------------------------------
// -- Album: // -- Album:
@@ -127,30 +128,30 @@ const routes: Routes = [
component: AlbumsScene, component: AlbumsScene,
canActivate: [OnlyUsersGuard], canActivate: [OnlyUsersGuard],
}, },
{
path: 'album/:albumId/edit',
component: AlbumEditScene,
canActivate: [OnlyAdminGuard],
},
{ {
path: 'album/:albumId', path: 'album/:albumId',
component: AlbumScene, component: AlbumScene,
canActivate: [OnlyUsersGuard], canActivate: [OnlyUsersGuard],
}, },
{
path: 'album-edit/:albumId',
component: AlbumEditScene,
canActivate: [OnlyAdminGuard],
},
// ------------------------------------ // ------------------------------------
// -- Tracks: // -- Tracks:
// ------------------------------------ // ------------------------------------
{
path: 'track/:trackId/edit',
component: TrackEditScene,
canActivate: [OnlyAdminGuard],
},
{ {
path: 'track/:genderId/:artistId/:albumId/:trackId', path: 'track/:genderId/:artistId/:albumId/:trackId',
component: TrackScene, component: TrackScene,
canActivate: [OnlyUsersGuard], canActivate: [OnlyUsersGuard],
}, },
{
path: 'track-edit/:trackId',
component: TrackEditScene,
canActivate: [OnlyAdminGuard],
},
// ------------------------------------ // ------------------------------------
// -- setting: // -- setting:
@@ -164,7 +165,6 @@ const routes: Routes = [
path: '**', path: '**',
component: NotFound404Scene, component: NotFound404Scene,
}, },
]; ];
@NgModule({ @NgModule({
@@ -181,5 +181,4 @@ const routes: Routes = [
] ]
}) })
export class AppRoutingModule { } export class AppRoutingModule { }
// export const routing: ModuleWithProviders = RouterModule.forRoot(routes);

View File

@@ -1,15 +1,17 @@
<!-- Generig global menu --> <!-- Generic global menu -->
<app-top-menu [menu]="currentMenu" (callback)="eventOnMenu($event)"></app-top-menu> <karcw-top-menu [menu]="currentMenu" (callback)="eventOnMenu($event)"/>
<!-- all interfaced pages --> <!-- all interfaced pages -->
<div class="main-content" *ngIf="autoConnectedDone"> <div class="main-content">
@if(autoConnectedDone) {
<router-outlet ></router-outlet> <router-outlet ></router-outlet>
</div> }
<div class="main-content" *ngIf="!autoConnectedDone"> @else {
<div class="generic-page"> <div class="generic-page">
<div class="fill-all colomn_mutiple"> <div class="fill-all colomn_mutiple">
<b style="color:red;">Auto-connection in progress</b> <b style="color:red;">Auto-connection in progress</b>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
</div> </div>
}
</div> </div>
<app-element-player-audio></app-element-player-audio> <app-element-player-audio></app-element-player-audio>

View File

@@ -5,12 +5,17 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { EventOnMenu } from 'common/component/top-menu/top-menu';
import { MenuItem, MenuPosition } from 'common/model';
import { UserService, SessionService, SSOService } from 'common/service';
import { isNullOrUndefined } from 'common/utils';
import { ArianeService } from './service'; import { ArianeService } from './service';
import { UserRoles222 } from 'common/service/session'; import {
MenuItem,
SSOService,
SessionService,
UserService,
UserRoles222,
EventOnMenu,
MenuPosition,
isNullOrUndefined,
} from '@kangaroo-and-rabbit/kar-cw';
enum MenuEventType { enum MenuEventType {
SSO_LOGIN = "SSO_CALL_LOGIN", SSO_LOGIN = "SSO_CALL_LOGIN",
@@ -40,10 +45,11 @@ export class AppComponent implements OnInit {
location: string = "home"; location: string = "home";
constructor( constructor(
private userService: UserService,
private sessionService: SessionService, private sessionService: SessionService,
private ssoService: SSOService, private ssoService: SSOService,
private arianeService: ArianeService) { private arianeService: ArianeService,
private userService: UserService
) {
} }
@@ -105,8 +111,7 @@ export class AppComponent implements OnInit {
} }
eventOnMenu(data: EventOnMenu): void { eventOnMenu(data: EventOnMenu): void {
//console.log(`plopppppppppp ${JSON.stringify(this.route.snapshot.url)}`); console.log(`Get event on menu: ${JSON.stringify(data, null, 4)}`);
//console.log(`Get event on menu: ${JSON.stringify(data, null, 4)}`);
switch (data.menu.otherData) { switch (data.menu.otherData) {
case MenuEventType.SSO_LOGIN: case MenuEventType.SSO_LOGIN:
this.ssoService.requestSignIn(); this.ssoService.requestSignIn();
@@ -145,15 +150,15 @@ export class AppComponent implements OnInit {
case MenuEventType.PLAYLIST: case MenuEventType.PLAYLIST:
break; break;
} }
} }
updateMainMenu(): void { updateMainMenu(): void {
console.log("update main menu :"); console.log("update main menu :");
if (this.isConnected) { if (this.isConnected) {
this.currentMenu = [ this.currentMenu = [
{ {
position: MenuPosition.LEFT, position: MenuPosition.LEFT,
hover: `You are logged as: ${this.sessionService.getLogin()}`, hover: "lkjljlk", //`You are logged as: ${this.sessionService.getLogin()}`,
icon: "menu", icon: "menu",
title: "Menu", title: "Menu",
subMenu: [ subMenu: [
@@ -201,7 +206,7 @@ export class AppComponent implements OnInit {
}, { }, {
position: MenuPosition.LEFT, position: MenuPosition.LEFT,
icon: "queue_music", icon: "queue_music",
title: this.arianeService.getPlaylistName(), title: "true",//this.arianeService.getPlaylistName(),
otherData: MenuEventType.PLAYLIST, otherData: MenuEventType.PLAYLIST,
callback: true, callback: true,
enable: !isNullOrUndefined(this.arianeService.getPlaylistId()), enable: !isNullOrUndefined(this.arianeService.getPlaylistId()),
@@ -287,7 +292,7 @@ export class AppComponent implements OnInit {
return "Tracks" return "Tracks"
} }
if (segment === "playlist") { if (segment === "playlist") {
return "Playlistq" return "Playlist"
} }
return ""; return "";
} }

View File

@@ -5,7 +5,7 @@
*/ */
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
@@ -22,8 +22,13 @@ import {
} from './scene'; } from './scene';
import { GenderService, DataService, PlaylistService, ArtistService, AlbumService, TrackService, ArianeService, PlayerService } from './service'; import { GenderService, DataService, PlaylistService, ArtistService, AlbumService, TrackService, ArianeService, PlayerService } from './service';
import { UploadScene } from './scene/upload/upload'; import { UploadScene } from './scene/upload/upload';
import { ElementSeriesComponent, ElementTrackComponent, ElementSeasonComponent, ElementVideoComponent, ElementPlayerAudioComponent } from './component'; import { ElementSeriesComponent, ElementTrackComponent, ElementSeasonComponent, ElementVideoComponent, ElementPlayerAudioComponent, DescriptionAreaComponent } from './component';
import { common_module_declarations, common_module_imports, common_module_providers, common_module_exports } from 'common/module'; import { KarCWModule } from '@kangaroo-and-rabbit/kar-cw';
import { environment } from 'environments/environment';
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";
@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -35,8 +40,8 @@ import { common_module_declarations, common_module_imports, common_module_provid
ElementSeasonComponent, ElementSeasonComponent,
ElementVideoComponent, ElementVideoComponent,
ElementPlayerAudioComponent, ElementPlayerAudioComponent,
DescriptionAreaComponent,
PopInCreateType, PopInCreateType,
HomeScene, HomeScene,
HelpScene, HelpScene,
GenderScene, GenderScene,
@@ -52,16 +57,21 @@ import { common_module_declarations, common_module_imports, common_module_provid
AlbumEditScene, AlbumEditScene,
ArtistEditScene, ArtistEditScene,
UploadScene, UploadScene,
...common_module_declarations,
], ],
imports: [ imports: [
FormsModule,
ReactiveFormsModule,
CommonModule,
BrowserModule, BrowserModule,
RouterModule, RouterModule,
AppRoutingModule, AppRoutingModule,
HttpClientModule, HttpClientModule,
...common_module_imports, KarCWModule,
], ],
providers: [ providers: [
{ provide: 'ENVIRONMENT', useValue: environment },
ArianeService,
PlayerService, PlayerService,
GenderService, GenderService,
DataService, DataService,
@@ -69,8 +79,6 @@ import { common_module_declarations, common_module_imports, common_module_provid
ArtistService, ArtistService,
AlbumService, AlbumService,
TrackService, TrackService,
ArianeService,
...common_module_providers,
], ],
exports: [ exports: [
AppComponent, AppComponent,
@@ -79,16 +87,10 @@ import { common_module_declarations, common_module_imports, common_module_provid
ElementSeasonComponent, ElementSeasonComponent,
ElementVideoComponent, ElementVideoComponent,
PopInCreateType, PopInCreateType,
...common_module_exports,
], ],
bootstrap: [ bootstrap: [
AppComponent AppComponent
], ],
/* schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA],
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
NO_ERRORS_SCHEMA
]
*/
}) })
export class AppModule { } export class AppModule { }

View File

@@ -0,0 +1,190 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Album, isAlbum, } from "./model"
export namespace AlbumResource {
/**
* Remove a specific album
*/
export function remove({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/album/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
});
};
/**
* Get a specific Album with his ID
*/
export function get({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
/**
* Update a specific album
*/
export function patch({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Album,
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isAlbum);
};
/**
* Add an album (when all the data already exist)
*/
export function post({ restConfig, data, }: {
restConfig: RESTConfig,
data: Album,
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
}, isAlbum);
};
/**
* Get all the available Albums
*/
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Album[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/album",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isAlbum);
};
/**
* Add a Track on a specific album
*/
export function addTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}/track/{trackId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
/**
* Remove a Track on a specific album
*/
export function removeTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}/track/{trackId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
/**
* Add a cover on a specific album
*/
export function uploadCover({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isAlbum);
};
/**
* Remove a cover on a specific album
*/
export function removeCover({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
coverId: UUID,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
}

View File

@@ -0,0 +1,127 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {Artist, UUID, Long, isArtist, } from "./model"
export namespace ArtistResource {
export function remove({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/artist/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
});
};
export function get({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isArtist);
};
export function patch({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Artist,
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isArtist);
};
export function post({ restConfig, data, }: {
restConfig: RESTConfig,
data: Artist,
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
}, isArtist);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Artist[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/artist",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isArtist);
};
export function uploadCover({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isArtist);
};
export function removeCover({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
coverId: UUID,
id: Long,
},
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isArtist);
};
}

View File

@@ -0,0 +1,104 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, } from "./model"
export namespace DataResource {
/**
* Insert a new data in the data environment
*/
export function uploadFile({ restConfig, data, }: {
restConfig: RESTConfig,
data: {
file: File,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/data//upload/",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
});
};
/**
* Get back some data from the data environment
*/
// TODO: unmanaged "Response" type: please specify @AsyncType or considered as 'void'.
export function retrieveDataId({ restConfig, queries, params, data, }: {
restConfig: RESTConfig,
queries: {
Authorization: string,
},
params: {
id: UUID,
},
data: string,
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/data/{id}",
requestType: HTTPRequestModel.GET,
},
restConfig,
params,
queries,
data,
});
};
/**
* Get a thumbnail of from the data environment (if resize is possible)
*/
// TODO: unmanaged "Response" type: please specify @AsyncType or considered as 'void'.
export function retrieveDataThumbnailId({ restConfig, queries, params, data, }: {
restConfig: RESTConfig,
queries: {
Authorization: string,
},
params: {
id: UUID,
},
data: string,
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/data/thumbnail/{id}",
requestType: HTTPRequestModel.GET,
},
restConfig,
params,
queries,
data,
});
};
/**
* Get back some data from the data environment (with a beautiful name (permit download with basic name)
*/
// TODO: unmanaged "Response" type: please specify @AsyncType or considered as 'void'.
export function retrieveDataFull({ restConfig, queries, params, data, }: {
restConfig: RESTConfig,
queries: {
Authorization: string,
},
params: {
name: string,
id: UUID,
},
data: string,
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/data/{id}/{name}",
requestType: HTTPRequestModel.GET,
},
restConfig,
params,
queries,
data,
});
};
}

View File

@@ -0,0 +1,8 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {} from "./model"
export namespace Front {
}

View File

@@ -0,0 +1,127 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Gender, isGender, } from "./model"
export namespace GenderResource {
export function remove({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/gender/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
});
};
export function get({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isGender);
};
export function patch({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Gender,
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isGender);
};
export function post({ restConfig, data, }: {
restConfig: RESTConfig,
data: Gender,
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
}, isGender);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Gender[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/gender",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isGender);
};
export function uploadCover({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isGender);
};
export function removeCover({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
coverId: UUID,
id: Long,
},
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isGender);
};
}

View File

@@ -0,0 +1,20 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {HealthResult, isHealthResult, } from "./model"
export namespace HealthCheck {
export function getHealth({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<HealthResult> {
return RESTRequestJson({
restModel: {
endPoint: "/health_check",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isHealthResult);
};
}

View File

@@ -0,0 +1,13 @@
/**
* Global import of the package
*/
export * from "./model";
export * from "./album-resource";
export * from "./artist-resource";
export * from "./front";
export * from "./gender-resource";
export * from "./health-check";
export * from "./playlist-resource";
export * from "./user-resource";
export * from "./track-resource";
export * from "./data-resource";

View File

@@ -0,0 +1,407 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
export const ZodUUID = zod.string().uuid();
export type UUID = zod.infer<typeof ZodUUID>;
export function isUUID(data: any): data is UUID {
try {
ZodUUID.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodLong = zod.number();
export type Long = zod.infer<typeof ZodLong>;
export function isLong(data: any): data is Long {
try {
ZodLong.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodInteger = zod.number().safe();
export type Integer = zod.infer<typeof ZodInteger>;
export function isInteger(data: any): data is Integer {
try {
ZodInteger.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodFloat = zod.number();
export type Float = zod.infer<typeof ZodFloat>;
export function isFloat(data: any): data is Float {
try {
ZodFloat.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodInstant = zod.string();
export type Instant = zod.infer<typeof ZodInstant>;
export function isInstant(data: any): data is Instant {
try {
ZodInstant.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodDate = zod.date();
export type Date = zod.infer<typeof ZodDate>;
export function isDate(data: any): data is Date {
try {
ZodDate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodTimestamp = zod.date();
export type Timestamp = zod.infer<typeof ZodTimestamp>;
export function isTimestamp(data: any): data is Timestamp {
try {
ZodTimestamp.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodLocalDate = zod.date();
export type LocalDate = zod.infer<typeof ZodLocalDate>;
export function isLocalDate(data: any): data is LocalDate {
try {
ZodLocalDate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodLocalTime = zod.date();
export type LocalTime = zod.infer<typeof ZodLocalTime>;
export function isLocalTime(data: any): data is LocalTime {
try {
ZodLocalTime.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodRestErrorResponse = zod.object({
uuid: ZodUUID.optional(),
time: zod.string().max(255).optional(),
error: zod.string().max(255).optional(),
message: zod.string().max(255).optional(),
status: ZodInteger,
statusMessage: zod.string().max(255).optional()
});
export type RestErrorResponse = zod.infer<typeof ZodRestErrorResponse>;
export function isRestErrorResponse(data: any): data is RestErrorResponse {
try {
ZodRestErrorResponse.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodGenericTiming = zod.object({
// Create time of the object
createdAt: ZodDate.readonly().optional(),
// When update the object
updatedAt: ZodDate.readonly().optional()
});
export type GenericTiming = zod.infer<typeof ZodGenericTiming>;
export function isGenericTiming(data: any): data is GenericTiming {
try {
ZodGenericTiming.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodGenericData = ZodGenericTiming.extend({
// Unique Id of the object
id: ZodLong.readonly().optional()
});
export type GenericData = zod.infer<typeof ZodGenericData>;
export function isGenericData(data: any): data is GenericData {
try {
ZodGenericData.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodGenericDataSoftDelete = ZodGenericData.extend({
// Deleted state
deleted: zod.boolean().readonly().optional()
});
export type GenericDataSoftDelete = zod.infer<typeof ZodGenericDataSoftDelete>;
export function isGenericDataSoftDelete(data: any): data is GenericDataSoftDelete {
try {
ZodGenericDataSoftDelete.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodNodeSmall = ZodGenericDataSoftDelete.extend({
name: zod.string().max(256).optional(),
description: zod.string().optional(),
// List of Id of the specific covers
covers: zod.array(ZodUUID).optional()
});
export type NodeSmall = zod.infer<typeof ZodNodeSmall>;
export function isNodeSmall(data: any): data is NodeSmall {
try {
ZodNodeSmall.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodAlbum = ZodNodeSmall.extend({
publication: ZodLocalDate.optional()
});
export type Album = zod.infer<typeof ZodAlbum>;
export function isAlbum(data: any): data is Album {
try {
ZodAlbum.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodArtist = ZodNodeSmall.extend({
firstName: zod.string().max(256).optional(),
surname: zod.string().max(256).optional(),
birth: ZodLocalDate.optional(),
death: ZodLocalDate.optional()
});
export type Artist = zod.infer<typeof ZodArtist>;
export function isArtist(data: any): data is Artist {
try {
ZodArtist.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodGender = ZodNodeSmall.extend({
});
export type Gender = zod.infer<typeof ZodGender>;
export function isGender(data: any): data is Gender {
try {
ZodGender.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodHealthResult = zod.object({
});
export type HealthResult = zod.infer<typeof ZodHealthResult>;
export function isHealthResult(data: any): data is HealthResult {
try {
ZodHealthResult.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodPlaylist = ZodNodeSmall.extend({
tracks: zod.array(ZodLong).optional()
});
export type Playlist = zod.infer<typeof ZodPlaylist>;
export function isPlaylist(data: any): data is Playlist {
try {
ZodPlaylist.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodUser = ZodGenericDataSoftDelete.extend({
login: zod.string().max(128).optional(),
lastConnection: ZodTimestamp.optional(),
admin: zod.boolean(),
blocked: zod.boolean(),
removed: zod.boolean(),
covers: zod.array(ZodLong).optional()
});
export type User = zod.infer<typeof ZodUser>;
export function isUser(data: any): data is User {
try {
ZodUser.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodUserKarusic = ZodUser.extend({
});
export type UserKarusic = zod.infer<typeof ZodUserKarusic>;
export function isUserKarusic(data: any): data is UserKarusic {
try {
ZodUserKarusic.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodUserOut = zod.object({
id: ZodLong,
login: zod.string().max(255).optional()
});
export type UserOut = zod.infer<typeof ZodUserOut>;
export function isUserOut(data: any): data is UserOut {
try {
ZodUserOut.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodTrack = ZodNodeSmall.extend({
genderId: ZodLong.optional(),
albumId: ZodLong.optional(),
track: ZodLong.optional(),
dataId: ZodUUID.optional(),
artists: zod.array(ZodLong).optional()
});
export type Track = zod.infer<typeof ZodTrack>;
export function isTrack(data: any): data is Track {
try {
ZodTrack.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodUUIDGenericData = ZodGenericTiming.extend({
// Unique UUID of the object
id: ZodUUID.readonly().optional()
});
export type UUIDGenericData = zod.infer<typeof ZodUUIDGenericData>;
export function isUUIDGenericData(data: any): data is UUIDGenericData {
try {
ZodUUIDGenericData.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodUUIDGenericDataSoftDelete = ZodUUIDGenericData.extend({
// Deleted state
deleted: zod.boolean().readonly().optional()
});
export type UUIDGenericDataSoftDelete = zod.infer<typeof ZodUUIDGenericDataSoftDelete>;
export function isUUIDGenericDataSoftDelete(data: any): data is UUIDGenericDataSoftDelete {
try {
ZodUUIDGenericDataSoftDelete.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}
export const ZodData = ZodUUIDGenericDataSoftDelete.extend({
// Sha512 of the data
sha512: zod.string().max(128).optional(),
// Mime -type of the media
mimeType: zod.string().max(128).optional(),
// Size in Byte of the data
size: ZodLong.optional()
});
export type Data = zod.infer<typeof ZodData>;
export function isData(data: any): data is Data {
try {
ZodData.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data ${e}`);
return false;
}
}

View File

@@ -0,0 +1,163 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Playlist, isPlaylist, } from "./model"
export namespace PlaylistResource {
export function remove({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/playlist/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
});
};
export function get({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function patch({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Playlist,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isPlaylist);
};
export function post({ restConfig, data, }: {
restConfig: RESTConfig,
data: Playlist,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
}, isPlaylist);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Playlist[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/playlist",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isPlaylist);
};
export function addTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}/track/{trackId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function removeTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}/track/{trackId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function uploadCover({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isPlaylist);
};
export function removeCover({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
coverId: UUID,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
}

View File

@@ -0,0 +1,246 @@
/** @file
* @author Edouard DUPIN
* @copyright 2024, Edouard DUPIN, all right reserved
* @license MPL-2
*/
import { RestErrorResponse } from "./model"
export enum HTTPRequestModel {
DELETE = 'DELETE',
GET = 'GET',
PATCH = 'PATCH',
POST = 'POST',
PUT = 'PUT',
}
export enum HTTPMimeType {
ALL = '*/*',
CSV = 'text/csv',
IMAGE = 'image/*',
IMAGE_JPEG = 'image/jpeg',
IMAGE_PNG = 'image/png',
JSON = 'application/json',
MULTIPART = 'multipart/form-data',
OCTET_STREAM = 'application/octet-stream',
TEXT_PLAIN = 'text/plain',
}
export interface RESTConfig {
// base of the server: http(s)://my.server.org/plop/api/
server: string;
// Token to access of the data.
token?: string;
}
export interface RESTModel {
// base of the local API request: "sheep/{id}".
endPoint: string;
// Type of the request.
requestType?: HTTPRequestModel;
// Input type requested.
accept?: HTTPMimeType;
// Content of the local data.
contentType?: HTTPMimeType;
// Mode of the TOKEN in urk or Header
tokenInUrl?: boolean;
}
export interface ModelResponseHttp {
status: number;
data: any;
}
export function isArrayOf<TYPE>(
data: any,
typeChecker: (subData: any) => subData is TYPE,
length?: number
): data is TYPE[] {
if (!Array.isArray(data)) {
return false;
}
if (!data.every(typeChecker)) {
return false;
}
if (length !== undefined && data.length != length) {
return false;
}
return true;
}
export type RESTRequestType = {
restModel: RESTModel,
restConfig: RESTConfig,
data?: any,
params?: object,
queries?: object,
};
function removeTrailingSlashes(input: string): string {
return input.replace(/\/+$/, '');
}
function removeLeadingSlashes(input: string): string {
return input.replace(/^\/+/, '');
}
export function RESTUrl({ restModel, restConfig, data, params, queries }: RESTRequestType): string {
// Create the URL PATH:
let generateUrl = `${removeTrailingSlashes(restConfig.server)}/${removeLeadingSlashes(restModel.endPoint)}`;
if (params !== undefined) {
for (let key of Object.keys(params)) {
generateUrl = generateUrl.replaceAll(`{${key}}`, `${params[key]}`);
}
}
if (queries === undefined && (restConfig.token === undefined || restModel.tokenInUrl !== true)) {
return generateUrl;
}
const searchParams = new URLSearchParams();
if (queries !== undefined) {
for (let key of Object.keys(queries)) {
const value = queries[key];
if (Array.isArray(value)) {
for (let iii = 0; iii < value.length; iii++) {
searchParams.append(`${key}`, `${value[iii]}`);
}
} else {
searchParams.append(`${key}`, `${value}`);
}
}
}
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
searchParams.append('Authorization', `Bearer ${restConfig.token}`);
}
return generateUrl + "?" + searchParams.toString();
}
export function RESTRequest({ restModel, restConfig, data, params, queries }: RESTRequestType): Promise<ModelResponseHttp> {
// Create the URL PATH:
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
let headers: any = {};
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
headers['Authorization'] = `Bearer ${restConfig.token}`;
}
if (restModel.accept !== undefined) {
headers['Accept'] = restModel.accept;
}
if (restModel.requestType !== HTTPRequestModel.GET) {
// if Get we have not a content type, the body is empty
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
headers['Content-Type'] = restModel.contentType;
}
}
let body = data;
if (restModel.contentType === HTTPMimeType.JSON) {
body = JSON.stringify(data);
} else if (restModel.contentType === HTTPMimeType.MULTIPART) {
const formData = new FormData();
for (const name in data) {
formData.append(name, data[name]);
}
body = formData
}
console.log(`Call ${generateUrl}`)
return new Promise((resolve, reject) => {
fetch(generateUrl, {
method: restModel.requestType,
headers,
body,
}).then((response: Response) => {
if (response.status >= 200 && response.status <= 299) {
const contentType = response.headers.get('Content-Type');
if (restModel.accept !== contentType) {
reject({
time: Date().toString(),
status: 901,
error: `REST check wrong type: ${restModel.accept} != ${contentType}`,
statusMessage: "Fetch error",
message: "rest-tools.ts Wrong type in the message return type"
} as RestErrorResponse);
} else if (contentType === HTTPMimeType.JSON) {
response
.json()
.then((value: any) => {
//console.log(`RECEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
resolve({ status: response.status, data: value });
})
.catch((reason: any) => {
reject({
time: Date().toString(),
status: 902,
error: `REST parse json fail: ${reason}`,
statusMessage: "Fetch parse error",
message: "rest-tools.ts Wrong message model to parse"
} as RestErrorResponse);
});
} else {
resolve({ status: response.status, data: response.body });
}
} else {
reject({
time: Date().toString(),
status: response.status,
error: `${response.body}`,
statusMessage: "Fetch code error",
message: "rest-tools.ts Wrong return code"
} as RestErrorResponse);
}
}).catch((error: any) => {
reject({
time: Date(),
status: 999,
error: error,
statusMessage: "Fetch catch error",
message: "http-wrapper.ts detect an error in the fetch request"
});
});
});
}
export function RESTRequestJson<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE> {
return new Promise((resolve, reject) => {
RESTRequest(request).then((value: ModelResponseHttp) => {
if (checker(value.data)) {
resolve(value.data);
} else {
reject({
time: Date().toString(),
status: 950,
error: "REST Fail to verify the data",
statusMessage: "API cast ERROR",
message: "api.ts Check type as fail"
} as RestErrorResponse);
}
}).catch((reason: RestErrorResponse) => {
reject(reason);
});
});
}
export function RESTRequestJsonArray<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE[]> {
return new Promise((resolve, reject) => {
RESTRequest(request).then((value: ModelResponseHttp) => {
if (isArrayOf(value.data, checker)) {
resolve(value.data);
} else {
reject({
time: Date().toString(),
status: 950,
error: "REST Fail to verify the data",
statusMessage: "API cast ERROR",
message: "api.ts Check type as fail"
} as RestErrorResponse);
}
}).catch((reason: RestErrorResponse) => {
reject(reason);
});
});
}
export function RESTRequestVoid(request: RESTRequestType): Promise<void> {
return new Promise((resolve, reject) => {
RESTRequest(request).then((value: ModelResponseHttp) => {
resolve();
}).catch((reason: RestErrorResponse) => {
reject(reason);
});
});
}

View File

@@ -0,0 +1,186 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Track, isTrack, } from "./model"
export namespace TrackResource {
export function remove({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/track/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
});
};
export function get({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function patch({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Track,
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isTrack);
};
export function post({ restConfig, data, }: {
restConfig: RESTConfig,
data: Track,
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
}, isTrack);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Track[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/track",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isTrack);
};
export function addTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
artistId: Long,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/artist/{artistId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function removeTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
artistId: Long,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/artist/{trackId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function uploadCover({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isTrack);
};
export function removeCover({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
coverId: UUID,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function uploadTrack({ restConfig, data, }: {
restConfig: RESTConfig,
data: {
fileName: string,
file: File,
gender: string,
artist: string,
album: string,
trackId: Long,
title: string,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/upload/",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
}, isTrack);
};
}

View File

@@ -0,0 +1,51 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UserOut, Long, UserKarusic, isUserOut, isUserKarusic, } from "./model"
export namespace UserResource {
export function get({ restConfig, params, produce, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
produce: HTTPMimeType.JSON,
}): Promise<UserKarusic> {
return RESTRequestJson({
restModel: {
endPoint: "/users/{id}",
requestType: HTTPRequestModel.GET,
accept: produce,
},
restConfig,
params,
}, isUserKarusic);
};
export function gets({ restConfig, produce, }: {
restConfig: RESTConfig,
produce: HTTPMimeType.JSON,
}): Promise<UserKarusic[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/users",
requestType: HTTPRequestModel.GET,
accept: produce,
},
restConfig,
}, isUserKarusic);
};
export function getMe({ restConfig, produce, }: {
restConfig: RESTConfig,
produce: HTTPMimeType.JSON,
}): Promise<UserOut> {
return RESTRequestJson({
restModel: {
endPoint: "/users/me",
requestType: HTTPRequestModel.GET,
accept: produce,
},
restConfig,
}, isUserOut);
};
}

View File

@@ -14,7 +14,7 @@ import { DataService } from 'app/service/data';
}) })
export class ElementDataImageComponent implements OnInit { export class ElementDataImageComponent implements OnInit {
// input parameters // input parameters
@Input() id:number = -1; @Input() id: string = "0";
cover: string = ''; cover: string = '';
/* /*
imageCanvas:any; imageCanvas:any;
@@ -29,11 +29,11 @@ export class ElementDataImageComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.cover = this.dataService.getCoverThumbnailUrl(this.id); this.cover = this.dataService.getThumbnailUrl(this.id);
/* /*
let canvas = this.imageCanvas.nativeElement; let canvas = this.imageCanvas.nativeElement;
let ctx = canvas.getContext("2d"); let ctx = canvas.getContext("2d");
console.log(`Request thumnail for ---> ${this.id}`); console.log(`Request thumbnail for ---> ${this.id}`);
this.dataService.getImageThumbnail(this.id) this.dataService.getImageThumbnail(this.id)
.then((result:ModelResponseHttp) => { .then((result:ModelResponseHttp) => {
console.log(`plop ---> ${result.status}`); console.log(`plop ---> ${result.status}`);

View File

@@ -0,0 +1,42 @@
<div class="fill-title">
<div class="description-area">
@if(title) {
<div class="shadow-text title">
{{title}}
</div>
}
@if(name) {
<div class="shadow-text sub-title-main">
{{name}}
</div>
}
@if(description) {
<div class="description">
{{description}}
</div>
}
<div class="button-area">
<button class="circular-button" (click)="playAll($event)" type="submit">
<i class="material-icons">play_arrow</i>
</button>
<button class="circular-button" (click)="playShuffle($event)" type="submit">
<i class="material-icons">shuffle</i>
</button>
<div style="flex:1;"></div>
</div>
</div>
@if (cover1 && cover1.length > 0) {
<div class="cover-area">
<div class="cover">
<img src="{{cover1[0]}}"/>
</div>
</div>
}
@if (cover2 && cover2.length > 0) {
<div class="cover-area">
<div class="cover">
<img src="{{cover2[0]}}"/>
</div>
</div>
}
</div>

View File

@@ -0,0 +1,31 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'description-area',
templateUrl: './description-area.html',
styleUrls: ['./description-area.less']
})
export class DescriptionAreaComponent {
@Input() title: string;
@Input() name?: string;
@Input() description?: string;
@Input() cover1?: number[];
@Input() cover2?: number[];
@Output() play = new EventEmitter<void>();
@Output() shuffle = new EventEmitter<void>();
playShuffle(event: any): void {
this.shuffle.emit();
}
playAll(event: any): void {
this.play.emit();
}
}

View File

@@ -1,6 +1,5 @@
<div class="bottom" *ngIf="mediaSource"> @if(mediaSource) {
<div class="media" > <div>
<div class="media-elem">
<audio width="1" height="1" src="{{mediaSource}}" <audio width="1" height="1" src="{{mediaSource}}"
#mediaPlayer #mediaPlayer
preload preload
@@ -11,36 +10,43 @@
(loadedmetadata)="changeMetadata()" (loadedmetadata)="changeMetadata()"
autoplay autoplay
(ended)="onAudioEnded()" (ended)="onAudioEnded()"
><!-- controls > --> <!--preload="none"--> >
<!--<p>Your browser does not support HTML5 media player. download media: <a href="{{mediaSource}}>link here</a>.</p>-->
</audio> </audio>
</div>
<div class="controls"> <div class="controls">
<div class="timer"> <div class="controls-inner">
<div class="timer-title"> <div class="title text-ellipsis">
<label class="unselectable label">{{nameData}}</label> <label class="unselectable">{{dataTitle}}</label>
</div> </div>
<div class="timer-lines"> <div class="text-ellipsis">
<label class="unselectable">{{dataAuthor}} / {{dataAlbum}}</label>
</div>
<div class="timer-slider">
<input type="range" min="0" class="slider" <input type="range" min="0" class="slider"
[value]="currentTime" [value]="currentTime"
[max]="duration" [max]="duration"
(input)="seek($event.target)"> (input)="seek($event.target)">
</div> </div>
<div class="timer-text"> <div class="flex-row">
<label class="unselectable label">{{currentTimeDisplay}} / {{durationDisplay}}</label> <label class="unselectable">{{currentTimeDisplay}}</label>
<label class="unselectable flex-row-last">{{durationDisplay}}</label>
</div> </div>
<div class="timer-control"> <div class="control">
<button (click)="onPlay()" *ngIf="!isPlaying" ><i class="material-icons">play_arrow</i></button> @if(!isPlaying) {
<button (click)="onPause()" *ngIf="isPlaying" ><i class="material-icons">pause</i></button> <button (click)="onPlay()"><i class="material-icons">play_arrow</i></button>
}
@else {
<button (click)="onPause()"><i class="material-icons">pause</i></button>
}
<button (click)="onStop()"><i class="material-icons">stop</i></button> <button (click)="onStop()"><i class="material-icons">stop</i></button>
<div style="margin:auto"></div>
<button [disabled]="havePrevious" (click)="onBefore()"><i class="material-icons">navigate_before</i></button> <button [disabled]="havePrevious" (click)="onBefore()"><i class="material-icons">navigate_before</i></button>
<button (click)="onRewind()"><i class="material-icons">fast_rewind</i></button> <button (click)="onRewind()"><i class="material-icons">fast_rewind</i></button>
<button (click)="onForward()"><i class="material-icons">fast_forward</i></button> <button (click)="onForward()"><i class="material-icons">fast_forward</i></button>
<button [disabled]="haveNext" (click)="onNext()"><i class="material-icons">navigate_next</i></button> <button [disabled]="haveNext" (click)="onNext()"><i class="material-icons">navigate_next</i></button>
<div style="margin:auto"></div>
<button (click)="onPlayMode()"><i class="material-icons">{{playMode}}</i></button> <button (click)="onPlayMode()"><i class="material-icons">{{playMode}}</i></button>
<!--<button (click)="onMore()" ><i class="material-icons">more_vert</i></button>-->
<!--<button (click)="onTakeScreenShoot()"><i class="material-icons">add_a_photo</i></button>-->
</div> </div>
</div> </div>
</div> </div>
</div> </div>
}

View File

@@ -1,10 +1,8 @@
.bottom {
.controls { .controls {
//visibility: hidden; //visibility: hidden;
opacity: 0.85; opacity: 0.85;
width: 96%; width: 96%;
height: 150px; //height: 150px;
border-radius: 10px; border-radius: 10px;
position: absolute; position: absolute;
bottom: 20px; bottom: 20px;
@@ -15,10 +13,25 @@
transition: 1s all; transition: 1s all;
display: flex; display: flex;
font-size: 40px; font-size: 40px;
min-width: 380px;
.controls-inner {
position: relative;
width: 100%;
height: 100%;
min-width: 350px;
font-family: monospace;
color: white;
margin: 10px 15px 1px 15px;
font-size: 20px;
}
.material-icons { .material-icons {
color: #FFF; color: #FFF;
font-size: 40px; font-size: 40px;
} }
button { button {
border: none; border: none;
background: none; background: none;
@@ -31,20 +44,10 @@
} }
} }
.slidecontainer {
line-height: 38px;
font-size: 10px;
font-family: monospace;
text-shadow: 1px 1px 0px black;
color: white;
flex: 5;
position: relative;
}
.slider { .slider {
position: relative; position: relative;
-webkit-appearance: none; //-webkit-appearance: none;
//width: calc(100% - 60px); width: 100%;
width: 95%;
height: 10px; height: 10px;
top: 5px; top: 5px;
border-radius: 5px; border-radius: 5px;
@@ -55,6 +58,7 @@
transition: opacity .2s; transition: opacity .2s;
flex: 5; flex: 5;
} }
.slider::-webkit-slider-thumb { .slider::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
@@ -73,87 +77,37 @@
cursor: pointer; cursor: pointer;
} }
.timer-title { .text-ellipsis {
position: absolute; overflow: hidden;
left: 30px; text-overflow: ellipsis;
width: 100%; white-space: nowrap;
font-size: 20px;
font-weight:bold;
bottom: 104px;
} }
.timer-lines {
position: absolute; .title {
left: 30px; font-size: 24px;
//width: calc(100%-60px);
font-size: 20px;
font-weight: bold; font-weight: bold;
bottom: 82px;
} }
.timer-text {
position: absolute; .timer-slider {
left: 30px;
width: 100%; width: 100%;
margin: 4px 0px 4px 0px;
font-size: 20px; font-size: 20px;
font-weight:bold; padding-bottom: 10px;
bottom: 40px;
} }
.timer-control {
position: absolute;
//top: 25px; .control {
left: 0px;
width: 100%; width: 100%;
//line-height: 38px;
font-size: 30px; font-size: 30px;
font-weight: bold; font-weight: bold;
bottom: 0px; display: flex;
} justify-content: center;
.label {
//transform: translate(-12px,-12px);
vertical-align: text-top;
line-height: 18px;
min-width: 50%;
//display: block,
} }
} }
/*
:hover .controls, :focus .controls {
opacity: 1;
}
*/
button:before { button:before {
font-family: HeydingsControlsRegular; font-family: HeydingsControlsRegular;
font-size: 30px; font-size: 30px;
position: relative; position: relative;
color: #FFF; color: #FFF;
//text-shadow: 1px 1px 0px black;
}
.timer {
line-height: 38px;
font-size: 30px;
font-family: monospace;
text-shadow: 1px 1px 0px black;
color: white;
flex: 5;
position: relative;
}
.timer div {
width:100%;
line-height: 38px;
font-size: 10px;
font-family: monospace;
text-shadow: 1px 1px 0px black;
color: white;
flex: 5;
position: relative;
}
.timer span {
position: absolute;
z-index: 3;
left: 19px;
}
} }

View File

@@ -3,16 +3,13 @@
* @copyright 2018, Edouard DUPIN, all right reserved * @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file) * @license PROPRIETARY (see license file)
*/ */
import { Component, OnInit, Input, ViewChild, ElementRef } from '@angular/core'; import { Component, OnInit, ViewChild, ElementRef, Inject } from '@angular/core';
import { isArray, isArrayOf, isNullOrUndefined, isNumberFinite } from 'common/utils';
import { NodeData } from 'common/model';
import { GenderService, DataService, PlayerService, TrackService, AlbumService, ArtistService } from 'app/service'; import { DataService, PlayerService, TrackService, AlbumService, ArtistService } from 'app/service';
import { PlaylistCurrent } from 'app/service/player'; import { PlaylistCurrent } from 'app/service/player';
import { Media } from 'app/model';
import { HttpWrapperService } from 'common/service';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { environment } from 'environments/environment'; import { Album, Artist, Track } from 'app/back-api';
import { isArray, isNullOrUndefined, Environment } from '@kangaroo-and-rabbit/kar-cw';
export enum PlayMode { export enum PlayMode {
@@ -43,14 +40,16 @@ export class ElementPlayerAudioComponent implements OnInit {
public name: string = 'rr'; public name: string = 'rr';
public description: string; public description: string;
public counttrack: number; public countTrack: number;
public covers: string[]; public covers: string[];
public volume_value: number = 100; public volume_value: number = 100;
public volume_displayMenu: boolean = false; public volume_displayMenu: boolean = false;
nameData: string; dataTitle: string;
dataAlbum: string;
dataAuthor: string;
playStream: boolean; playStream: boolean;
isPlaying: boolean; isPlaying: boolean;
currentTime: any; currentTime: any;
@@ -70,16 +69,16 @@ export class ElementPlayerAudioComponent implements OnInit {
} }
} }
constructor( constructor(
@Inject('ENVIRONMENT') private environment: Environment,
private playerService: PlayerService, private playerService: PlayerService,
private trackService: TrackService, private trackService: TrackService,
private dataService: DataService,
private albumService: AlbumService, private albumService: AlbumService,
private artistService: ArtistService, private artistService: ArtistService,
private httpService: HttpWrapperService,
private dataService: DataService,
private titleService: Title) { private titleService: Title) {
// nothing to do... // nothing to do...
} }
private currentLMedia: Media; private currentLMedia: Track;
private localIdStreaming: number; private localIdStreaming: number;
private localListStreaming: number[] = []; private localListStreaming: number[] = [];
ngOnInit() { ngOnInit() {
@@ -105,200 +104,54 @@ export class ElementPlayerAudioComponent implements OnInit {
this.havePrevious = this.localIdStreaming <= 0; this.havePrevious = this.localIdStreaming <= 0;
this.haveNext = this.localIdStreaming >= this.localListStreaming.length - 1; this.haveNext = this.localIdStreaming >= this.localListStreaming.length - 1;
this.trackService.get(this.localListStreaming[this.localIdStreaming]) this.trackService.get(this.localListStreaming[this.localIdStreaming])
.then((response: Media) => { .then((response: Track) => {
//console.log(`get response of video : ${ JSON.stringify(response, null, 2)}`); console.log(`get response of video : ${JSON.stringify(response, null, 2)}`);
self.currentLMedia = response; self.currentLMedia = response;
self.nameData = response.name; self.dataTitle = response.name;
if (!isNullOrUndefined(response.albumId)) { if (!isNullOrUndefined(response.albumId)) {
this.albumService.get(response.albumId) this.albumService.get(response.albumId)
.then((response2: NodeData) => { .then((response2: Album) => {
self.nameData = response2.name + " - " + self.nameData; self.dataAlbum = response2.name;
this.titleService.setTitle(`${environment.applName} > ${self.nameData}`) self.updateTitle();
}) })
.catch(() => { }); .catch(() => { });
} }
if (!isNullOrUndefined(response.artists) && isArray(response.artists) && response.artists.length > 0) { if (!isNullOrUndefined(response.artists) && isArray(response.artists) && response.artists.length > 0) {
this.artistService.get(response.artists[0]) this.artistService.get(response.artists[0])
.then((response2: NodeData) => { .then((response2: Artist) => {
self.nameData = `${self.nameData} (${response2.name})`; self.dataAuthor = response2.name;
this.titleService.setTitle(`${environment.applName} > ${self.nameData}`)
}) })
.catch(() => { }); .catch(() => { });
} }
if (isNullOrUndefined(self.currentLMedia)) { if (isNullOrUndefined(self.currentLMedia)) {
console.log("Can not retreive the media ...") console.log("Can not retrieve the media ...")
return; return;
} }
if (isNullOrUndefined(self.currentLMedia.dataId)) { if (isNullOrUndefined(self.currentLMedia.dataId)) {
console.log("Can not retreive the media ... null or undefined data ID") console.log("Can not retrieve the media ... null or undefined data ID")
return; return;
} }
self.mediaSource = self.httpService.createRESTCall2({ self.mediaSource = self.dataService.getUrl(self.currentLMedia.dataId, "unknownMediaName.webm");
api: `data/${self.currentLMedia.dataId}/unknowMediaName.webm`, //${self.generatedName}`, }).catch((error) => {
addURLToken: true, console.error(`error not unmanaged in audio player ... 111 ${error}`);
});
}).catch(() => {
console.error("error not ùmanaged in audio player ... 111");
}) })
} }
updateTitle() {
generateName() { let title = this.dataTitle;
/* if (!isNullOrUndefined(this.dataAlbum)) {
this.generatedName = ''; title = `${this.dataAlbum} - ${title}`;
if(this.seriesName !== undefined) {
this.generatedName = `${this.generatedName }${this.seriesName }-`;
} }
if(this.seasonName !== undefined) { if (!isNullOrUndefined(this.dataAuthor)) {
if(this.seasonName.length < 2) { title = `${title} (${this.dataAuthor})`;
this.generatedName = `${this.generatedName }s0${ this.seasonName }-`;
} else {
this.generatedName = `${this.generatedName }s${ this.seasonName }-`;
}
}
if(this.episode !== undefined) {
if(this.episode < 10) {
this.generatedName = `${this.generatedName }e0${ this.episode }-`;
} else {
this.generatedName = `${this.generatedName }e${ this.episode }-`;
}
}
this.generatedName = this.generatedName + this.name;
this.generatedName = this.generatedName.replace(new RegExp('&', 'g'), '_');
this.generatedName = this.generatedName.replace(new RegExp('/', 'g'), '_');
// update the path of the uri request
this.mediaSource = this.httpService.createRESTCall2({
api: `data/${ this.dataId}/${this.generatedName}`,
addURLToken: true,
});
*/
} }
myPeriodicCheckFunction() { this.titleService.setTitle(`${this.environment.applName} > ${title}`)
console.log('check ... ');
} }
changeMetadata() { changeMetadata() {
console.log('list of the stream:'); console.log('list of the stream:');
/*
let captureStream = this.audioPlayer.audioTracks;
for (let iii=0; iii < captureStream.length; iii++) {
console.log(" - " + captureStream[iii].language);
if (captureStream[iii].language.substring(0,2) === "fr") {
captureStream[iii].enabled = true;
} else {
captureStream[iii].enabled = false;
} }
} myPeriodicCheckFunction() {
*/ console.log('check ... ');
}
/*
ngOnInit() {
let self = this;
this.arianeService.updateManual(this.route.snapshot.paramMap);
this.idVideo = this.arianeService.getVideoId();
this.arianeService.mediaChange.subscribe((mediaId) => {
console.log(`Detect mediaId change...${ mediaId}`);
self.idVideo = mediaId;
self.updateDisplay();
});
self.updateDisplay();
}
*/
updateDisplay():void {
let self = this;
/*
self.haveNext = null;
self.havePrevious = null;
this.mediaService.get(this.idVideo)
.then((response) => {
console.log(`get response of media : ${ JSON.stringify(response, null, 2)}`);
self.error = '';
self.name = response.name;
self.description = response.description;
self.episode = response.episode;
self.seriesId = response.seriesId;
self.seasonId = response.seasonId;
self.dataId = response.dataId;
self.time = response.time;
self.generatedName = "????????? TODO: ???????" //response.generatedName;
if(self.dataId !== -1) {
self.mediaSource = self.httpService.createRESTCall2({
api: `data/${ self.dataId}/${self.generatedName}`,
addURLToken: true,
});
} else {
self.mediaSource = '';
}
self.covers = self.dataService.getCoverListUrl(response.covers);
self.generateName();
if(self.seriesId !== undefined && self.seriesId !== null) {
self.seriesService.get(self.seriesId)
.then((response2) => {
self.seriesName = response2.name;
self.generateName();
}).catch((response3) => {
// nothing to do ...
});
}
if(self.seasonId !== undefined && self.seasonId !== null) {
self.seasonService.get(self.seasonId)
.then((response4) => {
self.seasonName = response4.name;
self.generateName();
}).catch((response5) => {
// nothing to do ...
});
self.seasonService.getVideo(self.seasonId)
.then((response6:any) => {
// console.log("saison property: " + JSON.stringify(response, null, 2));
self.haveNext = null;
self.havePrevious = null;
for(let iii = 0; iii < response6.length; iii++) {
if(isNullOrUndefined(response6[iii].episode)) {
continue;
}
if(response6[iii].episode < self.episode) {
if(self.havePrevious === null) {
self.havePrevious = response6[iii];
} else if(self.havePrevious.episode < response6[iii].episode) {
self.havePrevious = response6[iii];
}
} else if(response6[iii].episode > self.episode) {
if(self.haveNext === null) {
self.haveNext = response6[iii];
} else if(self.haveNext.episode > response6[iii].episode) {
self.haveNext = response6[iii];
}
}
self.covers.push(self.dataService.getCoverUrl(response6[iii]));
}
}).catch((response7:any) => {
});
}
self.mediaIsLoading = false;
// console.log("display source " + self.mediaSource);
// console.log("set transformed : " + JSON.stringify(self, null, 2));
}).catch((response8) => {
self.error = 'Can not get the data';
self.name = '';
self.description = '';
self.episode = undefined;
self.seriesId = undefined;
self.seasonId = undefined;
self.dataId = -1;
self.time = undefined;
self.generatedName = '';
self.mediaSource = '';
self.covers = undefined;
self.seriesName = undefined;
self.seasonName = undefined;
self.mediaIsNotFound = true;
self.mediaIsLoading = false;
});
*/
} }
onRequirePlay() { onRequirePlay() {
this.playStream = true; this.playStream = true;
@@ -336,15 +189,15 @@ export class ElementPlayerAudioComponent implements OnInit {
this.isPlaying = false; this.isPlaying = false;
} }
convertIndisplayTime(time:number) : string { convertInDisplayTime(time: number): string {
let tmpp = parseInt(`${ time}`, 10); let temporaryValue = parseInt(`${time}`, 10);
let heures = parseInt(`${ tmpp / 3600}`, 10); let hours = parseInt(`${temporaryValue / 3600}`, 10);
tmpp = tmpp - heures * 3600; temporaryValue = temporaryValue - hours * 3600;
let minutes = parseInt(`${ tmpp / 60}`, 10); let minutes = parseInt(`${temporaryValue / 60}`, 10);
let seconds = tmpp - minutes * 60; let seconds = temporaryValue - minutes * 60;
let out = ''; let out = '';
if(heures !== 0) { if (hours !== 0) {
out = `${out }${heures }:`; out = `${out}${hours}:`;
} }
if (minutes >= 10) { if (minutes >= 10) {
out = `${out}${minutes}:`; out = `${out}${minutes}:`;
@@ -363,14 +216,14 @@ export class ElementPlayerAudioComponent implements OnInit {
// console.log("time change "); // console.log("time change ");
// console.log(" ==> " + this.audioPlayer.currentTime); // console.log(" ==> " + this.audioPlayer.currentTime);
this.currentTime = this.mediaPlayer.currentTime; this.currentTime = this.mediaPlayer.currentTime;
this.currentTimeDisplay = this.convertIndisplayTime(this.currentTime); this.currentTimeDisplay = this.convertInDisplayTime(this.currentTime);
// console.log(" ==> " + this.currentTimeDisplay); // console.log(" ==> " + this.currentTimeDisplay);
} }
changeDurationchange(duration: any) { changeDurationchange(duration: any) {
console.log('duration change '); console.log('duration change ');
console.log(` ==> ${this.mediaPlayer.duration}`); console.log(` ==> ${this.mediaPlayer.duration}`);
this.duration = this.mediaPlayer.duration; this.duration = this.mediaPlayer.duration;
this.durationDisplay = this.convertIndisplayTime(this.duration); this.durationDisplay = this.convertInDisplayTime(this.duration);
} }
onPlay() { onPlay() {
@@ -404,6 +257,10 @@ export class ElementPlayerAudioComponent implements OnInit {
onStop() { onStop() {
console.log('stop'); console.log('stop');
if (this.mediaPlayer.paused && this.mediaPlayer.currentTime == 0) {
this.mediaSource = null;
return;
}
if (isNullOrUndefined(this.mediaPlayer)) { if (isNullOrUndefined(this.mediaPlayer)) {
console.log(`error element: ${this.mediaPlayer}`); console.log(`error element: ${this.mediaPlayer}`);
return; return;
@@ -474,10 +331,11 @@ export class ElementPlayerAudioComponent implements OnInit {
// these element is to permit to not stop music when sceen is off !! // these element is to permit to not stop music when sceen is off !!
wakeLock = null; wakeLock = null;
unlockPlayerEnable() { unlockPlayerEnable() {
let tmppp = this.wakeLock; let temporaryValue = this.wakeLock;
this.wakeLock = null; this.wakeLock = null;
if (!isNullOrUndefined(tmppp)) { if (!isNullOrUndefined(temporaryValue)) {
tmppp.release(); console.log(`plopppp ${temporaryValue}`);
temporaryValue.release();
} }
try { try {
let tmp = navigator as any; let tmp = navigator as any;
@@ -487,11 +345,11 @@ export class ElementPlayerAudioComponent implements OnInit {
console.log(`Can not lock screen element: ${err.name}, ${err.message}`); console.log(`Can not lock screen element: ${err.name}, ${err.message}`);
} }
} }
lockPlayerEnable() { async lockPlayerEnable() {
if ('wakeLock' in navigator) { if ('wakeLock' in navigator) {
try { try {
let tmp = navigator as any; let tmp = navigator as any;
this.wakeLock = tmp.wakeLock.request('screen'); this.wakeLock = await tmp.wakeLock.request('screen');
} catch (err) { } catch (err) {
// The Wake Lock request has failed - usually system related, such as battery. // The Wake Lock request has failed - usually system related, such as battery.
console.log(`Can not lock screen element: ${err.name}, ${err.message}`); console.log(`Can not lock screen element: ${err.name}, ${err.message}`);

View File

@@ -1,41 +1,45 @@
<div class="imgContainer-small"> <div class="imgContainer-small">
<div *ngIf="covers"> @if(covers && covers.length > 0) {
<!--<data-image id="{{cover}}"></data-image>--> <div>
<img src="{{covers[0]}}"/> <img src="{{covers[0]}}"/>
</div> </div>
<div *ngIf="!covers" class="noImage"> }
@else {
</div> <div class="noImage"></div>
}
</div> </div>
<div class="season-small"> <div class="season-small">
{{prefixName}} {{numberAlbum}} {{prefixName}} {{numberAlbum}}
</div> </div>
<div class="description-small" *ngIf="countSubType && (!count || count == 0)"> @if(countSubType) {
<div class="description-small">
@if(!count || count == 0) {
No {{countSubType}} No {{countSubType}}
}
@else {
{{count}} {{countSubType}}{{count>1?"s":""}}
}
</div> </div>
<div class="description-small" *ngIf="countSubType && count > 1"> }
{{count}} {{countSubType}}s
</div>
<div class="description-small" *ngIf="countSubType && count == 1">
{{count}} {{countSubType}}
</div>
<div class="description-small" *ngIf="countSubType2 && (!count2 || count2 == 0)"> @if(countSubType2) {
<div class="description-small">
@if(!count2 || count2 == 0) {
No {{countSubType2}} No {{countSubType2}}
}
@else {
{{count2}} {{countSubType2}}{{count2>1?"s":""}}
}
</div> </div>
<div class="description-small" *ngIf="countSubType2 && count2 > 1"> }
{{count2}} {{countSubType2}}s @if(subValueData) {
</div> <div class="description-small">
<div class="description-small" *ngIf="countSubType2 && count2 == 1">
{{count2}} {{countSubType2}}
</div>
<div class="description-small" *ngIf="subValueData">
{{subValues}}: {{subValueData}} {{subValues}}: {{subValueData}}
</div> </div>
}
@if(!description) {
<div class="description-small" *ngIf="!description"> <div class="description-small">
{{description}} {{description}}
</div> </div>
}

View File

@@ -4,10 +4,11 @@
* @license PROPRIETARY (see license file) * @license PROPRIETARY (see license file)
*/ */
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
import { NodeSmall } from 'app/back-api';
import { AlbumService, DataService } from 'app/service'; import { AlbumService, DataService } from 'app/service';
import { NodeData } from 'common/model';
import { isNullOrUndefined } from 'common/utils';
@Component({ @Component({
selector: 'app-element-season', selector: 'app-element-season',
@@ -16,7 +17,7 @@ import { isNullOrUndefined } from 'common/utils';
}) })
export class ElementSeasonComponent implements OnInit { export class ElementSeasonComponent implements OnInit {
// input parameters // input parameters
@Input() element:NodeData; @Input() element: NodeSmall;
@Input() prefix: String; @Input() prefix: String;
@Input() countSubTypeCallBack: (arg0: number) => Promise<number>; @Input() countSubTypeCallBack: (arg0: number) => Promise<number>;
@Input() countSubType: String; @Input() countSubType: String;
@@ -42,6 +43,7 @@ export class ElementSeasonComponent implements OnInit {
this.prefix = this.prefixName ?? ""; this.prefix = this.prefixName ?? "";
this.count = undefined; this.count = undefined;
this.count2 = undefined; this.count2 = undefined;
//console.log(`element: ${JSON.stringify(this.element, null, 2)}`);
if (isNullOrUndefined(this.element)) { if (isNullOrUndefined(this.element)) {
this.numberAlbum = undefined; this.numberAlbum = undefined;
@@ -50,7 +52,7 @@ export class ElementSeasonComponent implements OnInit {
} }
this.numberAlbum = this.element.name; this.numberAlbum = this.element.name;
this.description = this.element.description; this.description = this.element.description;
this.covers = this.dataService.getCoverListThumbnailUrl(this.element.covers); this.covers = this.dataService.getListThumbnailUrl(this.element.covers);
let self = this; let self = this;
if (!isNullOrUndefined(this.countSubTypeCallBack)) { if (!isNullOrUndefined(this.countSubTypeCallBack)) {
this.countSubTypeCallBack(this.element.id) this.countSubTypeCallBack(this.element.id)

View File

@@ -1,24 +1,23 @@
<div> <div>
<div class="count-base"> <div class="count-base">
<div class="count" *ngIf="counttrack"> @if(countTrack) {
{{counttrack}} <div class="count">
{{countTrack}}
</div> </div>
}
</div> </div>
<div class="imgContainer-small"> <div class="imgContainer-small">
<div *ngIf="covers"> @if(covers && covers.length > 0) {
<div>
<!--<data-image id="{{cover}}"></data-image>--> <!--<data-image id="{{cover}}"></data-image>-->
<img src="{{covers[0]}}"/> <img src="{{covers[0]}}"/>
</div> </div>
<div *ngIf="!covers" class="noImage"> }
@else {
</div> <div class="noImage"></div>
}
</div> </div>
<div class="title-small"> <div class="title-small">
{{name}} {{name}}
</div> </div>
<!--
<div class="description-small" *ngIf="description">
{{description}}
</div>
-->
</div> </div>

View File

@@ -4,10 +4,10 @@
* @license PROPRIETARY (see license file) * @license PROPRIETARY (see license file)
*/ */
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { NodeData } from 'common/model';
import { isNullOrUndefined } from 'common/utils';
import { ArtistService, DataService } from 'app/service'; import { DataService, TrackService } from 'app/service';
import { NodeSmall } from 'app/back-api';
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
@Component({ @Component({
selector: 'app-element-series', selector: 'app-element-series',
@@ -16,16 +16,16 @@ import { ArtistService, DataService } from 'app/service';
}) })
export class ElementSeriesComponent implements OnInit { export class ElementSeriesComponent implements OnInit {
// input parameters // input parameters
@Input() element:NodeData; @Input() element: NodeSmall;
name: string = 'plouf'; name: string = 'plouf';
description: string = ''; description: string = '';
counttrack:number = null; countTrack: number = null;
covers: string[]; covers: string[];
constructor( constructor(
private artistService: ArtistService, private trackService: TrackService,
private dataService: DataService) { private dataService: DataService) {
} }
@@ -35,16 +35,15 @@ export class ElementSeriesComponent implements OnInit {
this.description = undefined; this.description = undefined;
return; return;
} }
let self = this; this.name = this.element.name;
self.name = this.element.name; this.description = this.element.description;
self.description = this.element.description; this.covers = this.dataService.getListThumbnailUrl(this.element.covers);
self.covers = self.dataService.getCoverListThumbnailUrl(this.element.covers);
this.artistService.countTrack(this.element.id) this.trackService.countTracksOfAnArtist(this.element.id)
.then((response) => { .then((response) => {
self.counttrack = response; this.countTrack = response;
}).catch((response) => { }).catch((response) => {
self.counttrack = 0; this.countTrack = 0;
}); });
} }
} }

View File

@@ -2,7 +2,9 @@
<div class="season-small"> <div class="season-small">
{{name}} {{name}}
</div> </div>
<div class="description-small" *ngIf="track"> @if(track) {
<div class="description-small">
n° {{track}} n° {{track}}
</div> </div>
}
</div> </div>

View File

@@ -4,10 +4,10 @@
* @license PROPRIETARY (see license file) * @license PROPRIETARY (see license file)
*/ */
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
import { NodeSmall } from 'app/back-api';
import { AlbumService, DataService } from 'app/service'; import { DataService } from 'app/service';
import { NodeData } from 'common/model';
import { isNullOrUndefined } from 'common/utils';
@Component({ @Component({
selector: 'app-element-track', selector: 'app-element-track',
@@ -16,7 +16,7 @@ import { isNullOrUndefined } from 'common/utils';
}) })
export class ElementTrackComponent implements OnInit { export class ElementTrackComponent implements OnInit {
// input parameters // input parameters
@Input() element:NodeData; @Input() element: NodeSmall;
@Input() prefix: String; @Input() prefix: String;
prefixName: string = ""; prefixName: string = "";
@@ -26,7 +26,6 @@ export class ElementTrackComponent implements OnInit {
description: string; description: string;
constructor( constructor(
private albumService: AlbumService,
private dataService: DataService) { private dataService: DataService) {
} }
@@ -40,7 +39,6 @@ export class ElementTrackComponent implements OnInit {
this.name = this.element.name; this.name = this.element.name;
this.description = this.element.description; this.description = this.element.description;
this.track = this.element["track"]; this.track = this.element["track"];
this.covers = this.dataService.getCoverListThumbnailUrl(this.element.covers); this.covers = this.dataService.getListThumbnailUrl(this.element.covers);
let self = this;
} }
} }

View File

@@ -1,16 +1,22 @@
<div> <div>
<div class="count-base" *ngIf="counttrack"> @if(countTrack) {
<span class="count">{{counttrack}}</span> <div class="count-base">
<span class="count">{{countTrack}}</span>
</div> </div>
}
<div class="imgContainer-small"> <div class="imgContainer-small">
<div *ngIf="covers"> @if(covers && covers.length > 0) {
<div>
<img src="{{covers[0]}}" class="miniature-small"/> <img src="{{covers[0]}}" class="miniature-small"/>
</div> </div>
}
</div> </div>
<div class="title-small"> <div class="title-small">
{{name}} {{name}}
</div> </div>
<div class="description-small" *ngIf="description"> @if(description) {
<div class="description-small">
{{description}} {{description}}
</div> </div>
}
</div> </div>

View File

@@ -4,10 +4,11 @@
* @license PROPRIETARY (see license file) * @license PROPRIETARY (see license file)
*/ */
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { isArrayOf, isNullOrUndefined, isNumberFinite } from 'common/utils';
import { NodeData } from 'common/model';
import { GenderService, DataService } from 'app/service'; import { DataService } from 'app/service';
import { NodeSmall } from 'app/back-api';
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
@Component({ @Component({
selector: 'app-element-type', selector: 'app-element-type',
@@ -16,18 +17,17 @@ import { GenderService, DataService } from 'app/service';
}) })
export class ElementTypeComponent implements OnInit { export class ElementTypeComponent implements OnInit {
// input parameters // input parameters
@Input() element:NodeData; @Input() element: NodeSmall;
@Input() functionVignette: (number) => Promise<Number>; @Input() functionVignette: (number) => Promise<Number>;
public name: string = 'rr'; public name: string = 'rr';
public description: string; public description: string;
public counttrack: number; public countTrack: number;
public covers: string[]; public covers: string[];
constructor( constructor(
private typeService: GenderService,
private dataService: DataService) { private dataService: DataService) {
} }
@@ -35,7 +35,7 @@ export class ElementTypeComponent implements OnInit {
if (isNullOrUndefined(this.element)) { if (isNullOrUndefined(this.element)) {
this.name = 'Not a media'; this.name = 'Not a media';
this.description = undefined; this.description = undefined;
this.counttrack = undefined; this.countTrack = undefined;
this.covers = undefined; this.covers = undefined;
return; return;
} }
@@ -43,14 +43,14 @@ export class ElementTypeComponent implements OnInit {
console.log(" ??? Get element ! " + JSON.stringify(this.element)); console.log(" ??? Get element ! " + JSON.stringify(this.element));
self.name = this.element.name; self.name = this.element.name;
self.description = this.element.description; self.description = this.element.description;
self.covers = self.dataService.getCoverListThumbnailUrl(this.element.covers); self.covers = self.dataService.getListThumbnailUrl(this.element.covers);
if (!isNullOrUndefined(this.functionVignette)) { if (!isNullOrUndefined(this.functionVignette)) {
this.functionVignette(this.element.id) this.functionVignette(this.element.id)
.then((response: number) => { .then((response: number) => {
self.counttrack = response; self.countTrack = response;
}).catch(() => { }).catch(() => {
self.counttrack = 0; self.countTrack = 0;
}); });
} }
} }

View File

@@ -1,22 +1,23 @@
<div> <div>
<div class="videoImgContainer"> <div class="videoImgContainer">
<div *ngIf="covers"> @if(covers && covers.length > 0) {
<div>
<!--<data-image id="{{cover}}"></data-image>--> <!--<data-image id="{{cover}}"></data-image>-->
<img src="{{covers[0]}}"/> <img src="{{covers[0]}}"/>
</div> </div>
<div *ngIf="!covers" class="noImage"> }
@else {
<div class="noImage"></div>
}
</div> </div>
</div> @if(element) {
<div class="title-small" *ngIf="data"> <div class="title-small">
{{episodeDisplay}} {{name}} {{episodeDisplay}} {{name}}
</div> </div>
<div class="title-small" *ngIf="!data"> }
@else {
<div class="title-small">
Error meda: {{element?.id}} Error meda: {{element?.id}}
</div> </div>
<!-- }
<div class="description-small" *ngIf="description">
{{description}}
</div>
-->
</div> </div>

View File

@@ -4,11 +4,9 @@
* @license PROPRIETARY (see license file) * @license PROPRIETARY (see license file)
*/ */
import { Injectable, Component, OnInit, Input } from '@angular/core'; import { Injectable, Component, OnInit, Input } from '@angular/core';
import { isMedia, Media } from 'app/model'; import { Track } from 'app/back-api';
import { DataService } from 'app/service'; import { DataService } from 'app/service';
import { NodeData } from 'common/model';
import { isNullOrUndefined } from 'common/utils';
@Component({ @Component({
selector: 'app-element-video', selector: 'app-element-video',
@@ -19,9 +17,7 @@ import { isNullOrUndefined } from 'common/utils';
@Injectable() @Injectable()
export class ElementVideoComponent implements OnInit { export class ElementVideoComponent implements OnInit {
// input parameters // input parameters
@Input() element:NodeData; @Input() element: Track;
data:Media;
name: string = ''; name: string = '';
description: string = ''; description: string = '';
episodeDisplay: string = ''; episodeDisplay: string = '';
@@ -34,20 +30,8 @@ export class ElementVideoComponent implements OnInit {
// nothing to do. // nothing to do.
} }
ngOnInit() { ngOnInit() {
if (!isMedia(this.element)) {
this.data = undefined;
this.name = 'Not a media';
this.description = undefined;
return;
}
this.data = this.element;
this.name = this.element.name; this.name = this.element.name;
this.description = this.element.description; this.description = this.element.description;
if(isNullOrUndefined(this.element.episode)) { this.covers = this.dataService.getListThumbnailUrl(this.element.covers);
this.episodeDisplay = '';
} else {
this.episodeDisplay = `${this.element.episode } - `;
}
this.covers = this.dataService.getCoverListThumbnailUrl(this.element.covers);
} }
} }

View File

@@ -1,3 +1,4 @@
import { DescriptionAreaComponent } from "./description-area/description-area";
import { ElementPlayerAudioComponent } from "./element-player-audio/element-player-audio"; import { ElementPlayerAudioComponent } from "./element-player-audio/element-player-audio";
import { ElementSeasonComponent } from "./element-season/element-season"; import { ElementSeasonComponent } from "./element-season/element-season";
import { ElementSeriesComponent } from "./element-series/element-series"; import { ElementSeriesComponent } from "./element-series/element-series";
@@ -12,5 +13,6 @@ export {
ElementSeasonComponent, ElementSeasonComponent,
ElementPlayerAudioComponent, ElementPlayerAudioComponent,
ElementTrackComponent, ElementTrackComponent,
DescriptionAreaComponent,
}; };

View File

@@ -1,34 +0,0 @@
import { isArrayOf, isNumberFinite, isObject, isOptionalOf, isOptionalArrayOf, isString } from "common/utils";
export interface AlbumModel {
id: number;
name: string;
description?: string;
covers?: number[];
tracks?: number[];
};
export function isAlbumModel(data: any): data is AlbumModel {
if (!isObject(data)) {
return false;
}
if (!isNumberFinite(data.id)) {
return false;
}
if (!isString(data.name)) {
return false;
}
if (!isOptionalOf(data.description, isString)) {
return false;
}
if (!isOptionalArrayOf(data.cover, isNumberFinite)) {
return false;
}
if (!isOptionalArrayOf(data.tracks, isNumberFinite)) {
return false;
}
return true;
}

View File

@@ -1,5 +0,0 @@
import { Media, isMedia } from "./media";
export {
Media, isMedia,
}

View File

@@ -1,47 +0,0 @@
import { isNumberFinite, isString, isOptionalOf, isArray } from "common/utils";
import { isNodeData, NodeData } from "common/model/node";
export interface Media extends NodeData {
dataId?: number;
genderId?: number;
artists?: number[];
albumId?: number;
episode?: number;
track?: number;
date?: number;
time?: number;
};
export function isMedia(data: any): data is Media {
if (!isNodeData(data) as any) {
return false;
}
if (!isOptionalOf(data.dataId, isNumberFinite)) {
return false;
}
if (!isOptionalOf(data.typeId, isNumberFinite)) {
return false;
}
if (!isOptionalOf(data.artists, isArray)) {
return false;
}
if (!isOptionalOf(data.albumId, isNumberFinite)) {
return false;
}
if (!isOptionalOf(data.track, isNumberFinite)) {
return false;
}
if (!isOptionalOf(data.episode, isNumberFinite)) {
return false;
}
if (!isOptionalOf(data.date, isNumberFinite)) {
return false;
}
if (!isOptionalOf(data.time, isNumberFinite)) {
return false;
}
return true;
}

View File

@@ -4,8 +4,7 @@
* @license PROPRIETARY (see license file) * @license PROPRIETARY (see license file)
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { PopInService } from '@kangaroo-and-rabbit/kar-cw';
import { PopInService } from 'common/service/popin';
@Component({ @Component({
selector: 'create-type', selector: 'create-type',

View File

@@ -2,21 +2,26 @@
<div class="title"> <div class="title">
Edit album Edit album
</div> </div>
<div class="fill-all" *ngIf="itemIsRemoved"> @if(itemIsRemoved) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
The album has been removed The album has been removed
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="itemIsNotFound"> }
@else if (itemIsNotFound) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
The album does not exist The album does not exist
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="itemIsLoading"> }
@else if (itemIsLoading) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
Loading ...<br/> Loading ...<br/>
@@ -24,7 +29,9 @@
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> }
@else {
<div class="fill-all">
<div class="request_raw"> <div class="request_raw">
<div class="label"> <div class="label">
name: name:
@@ -68,10 +75,10 @@
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<!-- ------------------------- Cover section --------------------------------- --> <!-- ------------------------- Cover section --------------------------------- -->
<div class="title" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="title">
Covers Covers
</div> </div>
<div class="fill-all" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="fill-all">
<div class="hide-element"> <div class="hide-element">
<input type="file" <input type="file"
#fileInput #fileInput
@@ -81,7 +88,8 @@
</div> </div>
<div class="request_raw"> <div class="request_raw">
<div class="input"> <div class="input">
<div class="cover" *ngFor="let element of coversDisplay"> @for (element of coversDisplay; track element.id;) {
<div class="cover">
<div class="cover-image"> <div class="cover-image">
<img src="{{element.url}}"/> <img src="{{element.url}}"/>
</div> </div>
@@ -91,6 +99,7 @@
</button> </button>
</div> </div>
</div> </div>
}
<div class="cover"> <div class="cover">
<div class="cover-no-image"> <div class="cover-no-image">
</div> </div>
@@ -105,10 +114,10 @@
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<!-- ------------------------- ADMIN section --------------------------------- --> <!-- ------------------------- ADMIN section --------------------------------- -->
<div class="title" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="title">
Administration Administration
</div> </div>
<div class="fill-all" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="fill-all">
<div class="request_raw"> <div class="request_raw">
<div class="label"> <div class="label">
<i class="material-icons">data_usage</i> ID: <i class="material-icons">data_usage</i> ID:
@@ -131,17 +140,22 @@
<div class="label"> <div class="label">
<i class="material-icons">delete_forever</i> Trash: <i class="material-icons">delete_forever</i> Trash:
</div> </div>
<div class="input" *ngIf="(trackCount == '0')"> @if(trackCount == '0') {
<div class="input">
<button class="button color-button-cancel color-shadow-black" (click)="removeItem()" type="submit"> <button class="button color-button-cancel color-shadow-black" (click)="removeItem()" type="submit">
<i class="material-icons">delete</i> Remove album <i class="material-icons">delete</i> Remove album
</button> </button>
</div> </div>
<div class="input" *ngIf="(trackCount != '0')"> }
@else {
<div class="input">
<i class="material-icons">new_releases</i> Can not remove album, track depending on it <i class="material-icons">new_releases</i> Can not remove album, track depending on it
</div> </div>
}
</div> </div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
}
</div> </div>
<upload-progress [mediaTitle]="upload.labelMediaTitle" <upload-progress [mediaTitle]="upload.labelMediaTitle"
[mediaUploaded]="upload.mediaSendSize" [mediaUploaded]="upload.mediaSendSize"

View File

@@ -5,12 +5,11 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { UploadProgress, PopInService } from '@kangaroo-and-rabbit/kar-cw';
import { Album } from 'app/back-api';
import { AlbumService, ArianeService, DataService } from 'app/service'; import { AlbumService, ArianeService, DataService, TrackService } from 'app/service';
import { NodeData } from 'common/model';
import { UploadProgress } from 'common/popin/upload-progress/upload-progress';
import { PopInService } from 'common/service';
export interface ElementList { export interface ElementList {
value: number; value: number;
@@ -45,7 +44,7 @@ export class AlbumEditScene implements OnInit {
// --------------- confirm section ------------------ // --------------- confirm section ------------------
public confirmDeleteComment: string = null; public confirmDeleteComment: string = null;
public confirmDeleteImageUrl: string = null; public confirmDeleteImageUrl: string = null;
private deleteCoverId: number = null; private deleteCoverId: string = null;
private deleteItemId: number = null; private deleteItemId: number = null;
deleteConfirmed() { deleteConfirmed() {
if (this.deleteCoverId !== null) { if (this.deleteCoverId !== null) {
@@ -67,6 +66,7 @@ export class AlbumEditScene implements OnInit {
constructor( constructor(
private albumService: AlbumService, private albumService: AlbumService,
private trackService: TrackService,
private arianeService: ArianeService, private arianeService: ArianeService,
private popInService: PopInService, private popInService: PopInService,
private dataService: DataService) { private dataService: DataService) {
@@ -77,7 +77,7 @@ export class AlbumEditScene implements OnInit {
this.idAlbum = this.arianeService.getAlbumId(); this.idAlbum = this.arianeService.getAlbumId();
let self = this; let self = this;
this.albumService.get(this.idAlbum) this.albumService.get(this.idAlbum)
.then((response: NodeData) => { .then((response: Album) => {
console.log(`get response of album : ${JSON.stringify(response, null, 2)}`); console.log(`get response of album : ${JSON.stringify(response, null, 2)}`);
self.nameAlbum = response.name; self.nameAlbum = response.name;
self.description = response.description; self.description = response.description;
@@ -91,7 +91,7 @@ export class AlbumEditScene implements OnInit {
self.itemIsNotFound = true; self.itemIsNotFound = true;
self.itemIsLoading = false; self.itemIsLoading = false;
}); });
this.albumService.getTrack(this.idAlbum) this.trackService.getTracksWithAlbumId(this.idAlbum)
.then((response: any) => { .then((response: any) => {
self.trackCount = response.length; self.trackCount = response.length;
}).catch((response: any) => { }).catch((response: any) => {
@@ -105,7 +105,7 @@ export class AlbumEditScene implements OnInit {
for (let iii = 0; iii < covers.length; iii++) { for (let iii = 0; iii < covers.length; iii++) {
this.coversDisplay.push({ this.coversDisplay.push({
id: covers[iii], id: covers[iii],
url: this.dataService.getCoverThumbnailUrl(covers[iii]) url: this.dataService.getThumbnailUrl(covers[iii])
}); });
} }
} else { } else {
@@ -165,7 +165,7 @@ export class AlbumEditScene implements OnInit {
this.upload.clear(); this.upload.clear();
// display the upload pop-in // display the upload pop-in
this.popInService.open('popin-upload-progress'); this.popInService.open('popin-upload-progress');
this.albumService.uploadCover(file, this.idAlbum, (count, total) => { this.albumService.uploadCover(this.idAlbum, file, (count, total) => {
self.upload.mediaSendSize = count; self.upload.mediaSendSize = count;
self.upload.mediaSize = total; self.upload.mediaSize = total;
}) })
@@ -179,14 +179,14 @@ export class AlbumEditScene implements OnInit {
}); });
} }
removeCover(id: number) { removeCover(id: string) {
this.cleanConfirm(); this.cleanConfirm();
this.confirmDeleteComment = `Delete the cover ID: ${id}`; this.confirmDeleteComment = `Delete the cover ID: ${id}`;
this.confirmDeleteImageUrl = this.dataService.getCoverThumbnailUrl(id); this.confirmDeleteImageUrl = this.dataService.getThumbnailUrl(id);
this.deleteCoverId = id; this.deleteCoverId = id;
this.popInService.open('popin-delete-confirm'); this.popInService.open('popin-delete-confirm');
} }
removeCoverAfterConfirm(id: number) { removeCoverAfterConfirm(id: string) {
console.log(`Request remove cover: ${id}`); console.log(`Request remove cover: ${id}`);
let self = this; let self = this;
this.albumService.deleteCover(this.idAlbum, id) this.albumService.deleteCover(this.idAlbum, id)

View File

@@ -1,40 +1,26 @@
<div class="generic-page"> <div class="generic-page">
<div class="fill-title colomn_mutiple">
<div class="cover-area"> <description-area
<div class="cover" *ngIf="covers" > [title]="name"
<img src="{{covers[0]}}"/> [name]="albumName"
</div> [description]="albumDescription"
</div> [cover1]="artistCovers"
<div [className]="covers ? 'description-area description-area-cover' : 'description-area description-area-no-cover'"> [cover2]="albumCovers"
<div class="title"> (play)="playAll()"
{{name}} (shuffle)="playShuffle()"/>
</div> @if (tracks) {
<div class="title"> <div class="fill-content colomn_single">
{{albumName}}
</div>
<div class="description" *ngIf="albumDescription">
{{albumDescription}}
</div>
<div class="description" *ngIf="albumDescription">
{{albumDescription}}
</div>
<button class="button color-button color-shadow-black" (click)="playAll($event)" type="submit">
<i class="material-icons">play_arrow</i> Play All
</button>
<button class="button color-button color-shadow-black" style="margin-left:10px;" (click)="playShuffe($event)" type="submit">
<i class="material-icons">shuffle</i> Shuffle
</button>
</div>
</div>
<div class="fill-content colomn_mutiple" *ngIf="tracks">
<div class="clear"></div> <div class="clear"></div>
<div class="title" *ngIf="tracks.length > 1">Tracks:</div> <div class="title">Track{{tracks.length > 1?"s":""}}:</div>
<div class="title" *ngIf="tracks.length == 1">Track:</div> @for (data of tracks; track data.id;) {
<app-element-track <app-element-track
*ngFor="let data of tracks"
[element]="data" [element]="data"
(click)="onSelectTrack($event, data.id)" (click)="onSelectTrack($event, data.id)"
(auxclick)="onSelectTrack($event, data.id)"></app-element-track> (auxclick)="onSelectTrack($event, data.id)"/>
} @empty {
Aucune piste accessible.
}
</div> </div>
}
<div class="clear-end"></div> <div class="clear-end"></div>
</div> </div>

View File

@@ -5,27 +5,28 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Media } from 'app/model'; import { Album, Track } from 'app/back-api';
import { arrayUnique } from '@kangaroo-and-rabbit/kar-cw';
import { ArtistService, DataService, ArianeService, AlbumService, TrackService, PlayerService } from 'app/service'; import { ArtistService, DataService, ArianeService, AlbumService, TrackService, PlayerService } from 'app/service';
@Component({ @Component({
selector: 'app-album', selector: 'app-album',
templateUrl: './album.html' templateUrl: './album.html',
}) })
export class AlbumScene implements OnInit { export class AlbumScene implements OnInit {
public idArtist = -1; public artistIds: number[] = [];
public idAlbum = -1; public idAlbum: number = -1;
public name: string = ''; public name: string = '???';
public description: string = undefined; public description: string = undefined;
public covers: Array<string> = undefined; public artistCovers: Array<string> = undefined;
public albumName: string = ''; public albumName: string = '';
public albumDescription: string = undefined; public albumDescription: string = undefined;
public albumCovers: string[] = undefined; public albumCovers: string[] = undefined;
public tracksIds: number[] = undefined; public tracksIds: number[] = undefined;
public tracks: Media[] = undefined; public tracks: Track[] = undefined;
constructor( constructor(
private artistService: ArtistService, private artistService: ArtistService,
@@ -34,42 +35,53 @@
private arianeService: ArianeService, private arianeService: ArianeService,
private playerService: PlayerService, private playerService: PlayerService,
private dataService: DataService) { private dataService: DataService) {
} }
ngOnInit() { ngOnInit() {
// this.idPlaylist = parseInt(this.route.snapshot.paramMap.get('universId')); //this.artistIds = [this.arianeService.getArtistId()];
// this.idType = parseInt(this.route.snapshot.paramMap.get('typeId'));
this.idArtist = this.arianeService.getArtistId();
this.idAlbum = this.arianeService.getAlbumId(); this.idAlbum = this.arianeService.getAlbumId();
let self = this; let self = this;
this.artistService.get(this.idArtist)
.then((response) => {
self.name = response.name;
self.description = response.description;
self.covers = this.dataService.getCoverListUrl(response.covers);
}).catch((response) => {
self.description = undefined;
self.name = '???';
self.covers = undefined;
// no check just ==> an error occured on album
});
this.albumService.get(this.idAlbum) this.albumService.get(this.idAlbum)
.then((response) => { .then((response) => {
self.albumName = response.name; self.albumName = response.name;
self.albumDescription = response.description; self.albumDescription = response.description;
self.albumCovers = this.dataService.getCoverListUrl(response.covers); self.albumCovers = this.dataService.getListUrl(response.covers);
}).catch((response) => { }).catch((error) => {
self.albumDescription = undefined; self.albumDescription = undefined;
self.albumName = '???'; self.albumName = '???';
self.albumCovers = undefined; self.albumCovers = undefined;
// no check just ==> an error occured on album // no check just ==> an error occurred on album
}); });
//console.log("all the tracks: " + self.tracksIds); console.log(`all the tracks for a specific album: ${self.idAlbum}`);
this.trackService.getWithAlbum(self.idAlbum) this.trackService.getTracksWithAlbumId(self.idAlbum)
.then((response2: Media[]) => { .then((response2: Track[]) => {
self.tracks = response2; self.tracks = response2;
console.log(`get tracks : ${JSON.stringify(self.tracks, null, 2)}`);
self.artistIds = []
self.tracks.forEach(element => {
self.artistIds = [...self.artistIds, ...element.artists];
});
self.artistIds = arrayUnique(self.artistIds);
if (self.artistIds.length === 0) {
console.error("No artist found !!!");
return;
} else if (self.artistIds.length > 1) {
console.error("More than 1 artist ==> not managed");
}
/*
// TODO: display more than 1 ...
self.artistService.get(self.artistIds[0])
.then((response) => {
self.name = response.name;
self.description = response.description;
self.artistCovers = self.dataService.getListUrl(response.covers);
}).catch((error) => {
self.description = undefined;
self.name = '???';
self.artistCovers = undefined;
});
*/
//console.log(`>>>>BBB get tracks : ${JSON.stringify(response2, null, 2)}`); //console.log(`>>>>BBB get tracks : ${JSON.stringify(response2, null, 2)}`);
}).catch((response) => { }).catch((response) => {
//console.log(`>>>>BBB plop`); //console.log(`>>>>BBB plop`);
@@ -99,7 +111,7 @@
this.arianeService.navigateTrackEdit({ id: idSelected, newWindows: event.which === 2 }); this.arianeService.navigateTrackEdit({ id: idSelected, newWindows: event.which === 2 });
} }
} }
playAll(event: any):void { playAll(): void {
let elements: number[] = []; let elements: number[] = [];
for (let iii = 0; iii < this.tracks.length; iii++) { for (let iii = 0; iii < this.tracks.length; iii++) {
elements.push(this.tracks[iii].id); elements.push(this.tracks[iii].id);
@@ -107,7 +119,7 @@
this.playerService.clear(); this.playerService.clear();
this.playerService.setNewPlaylist(elements); this.playerService.setNewPlaylist(elements);
} }
playShuffe(event: any):void { playShuffle(): void {
let elements: number[] = []; let elements: number[] = [];
for (let iii = 0; iii < this.tracks.length; iii++) { for (let iii = 0; iii < this.tracks.length; iii++) {
elements.push(this.tracks[iii].id); elements.push(this.tracks[iii].id);
@@ -116,5 +128,3 @@
this.playerService.setNewPlaylistShuffle(elements); this.playerService.setNewPlaylistShuffle(elements);
} }
} }

View File

@@ -1,48 +1,40 @@
<div class="generic-page"> <div class="generic-page">
<div class="fill-title colomn_mutiple"> <description-area
<div class="cover-area"> [title]="name"
<div class="cover" *ngIf="covers" > [description]="description"
<img src="{{covers[0]}}"/> [cover1]="covers"
</div> (play)="playAll()"
</div> (shuffle)="playShuffle()"/>
<div [className]="covers ? 'description-area description-area-cover' : 'description-area description-area-no-cover'"> @if(albums) {
<div class="title"> <div class="fill-content colomn_single">
{{name}}
</div>
<div class="description" *ngIf="description">
{{description}}
</div>
<button class="button color-button color-shadow-black" (click)="playAll($event)" type="submit">
<i class="material-icons">play_arrow</i> Play All
</button>
<button class="button color-button color-shadow-black" style="margin-left:10px;" (click)="playShuffe($event)" type="submit">
<i class="material-icons">shuffle</i> Shuffle
</button>
</div>
</div>
<div class="fill-content colomn_mutiple" *ngIf="albums">
<div class="clear"></div> <div class="clear"></div>
<div class="title" *ngIf="albums.length > 1">Albums:</div> <div class="title">Album{{albums.length > 1?"s":""}}: <app-entry placeholder="Search..." (changeValue)="onSearch($event)"></app-entry></div>
<div class="title" *ngIf="albums.length == 1">Album:</div> @for (data of albums; track data.id;) {
<div *ngFor="let data of albums" class="item-list" (click)="onSelectAlbum($event, data.id)" (auxclick)="onSelectAlbum($event, data.id)"> <div class="item-list"
(click)="onSelectAlbum($event, data.id)"
(auxclick)="onSelectAlbum($event, data.id)"
>
<app-element-season <app-element-season
[element]="data" [element]="data"
countSubType="Track" countSubType="Track"
[countSubTypeCallBack]="countTrack" [countSubTypeCallBack]="countTrack"
subValues="Artist" subValues="Artist"
[subValuesCallBack]="getArtistsString" [subValuesCallBack]="getArtistsString"/>
></app-element-season>
</div> </div>
}
</div> </div>
<div class="fill-content colomn_mutiple" *ngIf="tracks"> }
@if(tracks) {
<div class="fill-content colomn_mutiple">
<div class="clear"></div> <div class="clear"></div>
<div class="title" *ngIf="tracks.length > 1">Tracks:</div> <div class="title">Track{{tracks.length > 1?"s":""}}:</div>
<div class="title" *ngIf="tracks.length == 1">Track:</div> @for (data of tracks; track data.id;) {
<div *ngFor="let data of tracks" class="item item-video" (click)="onSelectTrack($event, data.id)" (auxclick)="onSelectTrack($event, data.id)"> <div class="item item-video" (click)="onSelectTrack($event, data.id)" (auxclick)="onSelectTrack($event, data.id)">
<app-element-video <app-element-video
[element]="data" [element]="data"/>
></app-element-video>
</div> </div>
}
</div> </div>
}
<div class="clear-end"></div> <div class="clear-end"></div>
</div> </div>

View File

@@ -5,9 +5,10 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { DataTools } from '@kangaroo-and-rabbit/kar-cw';
import { Album, Artist, Track } from 'app/back-api';
import { ArtistService, DataService, ArianeService, AlbumService, PlayerService, TrackService } from 'app/service'; import { ArtistService, DataService, ArianeService, AlbumService, PlayerService, TrackService } from 'app/service';
import { NodeData } from 'common/model';
@Component({ @Component({
selector: 'app-albums', selector: 'app-albums',
@@ -18,7 +19,8 @@
public name: string = ''; public name: string = '';
public description: string = undefined; public description: string = undefined;
public covers: string[] = undefined; public covers: string[] = undefined;
public albums: NodeData[] = undefined; public albums: Album[] = undefined;
public albumsSave: Album[] = undefined;
public tracks: any[] = undefined; public tracks: any[] = undefined;
public countSubElement: number = undefined; public countSubElement: number = undefined;
countTrack: (id: number) => Promise<Number>; countTrack: (id: number) => Promise<Number>;
@@ -35,29 +37,44 @@
} }
countTrackCallback(albumId: number): Promise<Number> { countTrackCallback(albumId: number): Promise<Number> {
return this.albumService.countTrack(albumId); return this.trackService.countTracksWithAlbumId(albumId);
} }
getArtistsStringCallback(albumId: number): Promise<String[]> { getArtistsStringCallback(albumId: number): Promise<String[]> {
//console.log(`request all artist for album: {albumId}`) //console.log(`request all artist for album: {albumId}`)
return this.albumService.getArtists(albumId); let self = this;
return new Promise((resolve, reject) => {
self.trackService.getTracksWithAlbumId(albumId)
.then((response: Track[]) => {
const listArtists = DataTools.extractLimitOneList(response, "artists");
self.artistService.getAll(listArtists)
.then((listArtists: Artist[]) => {
resolve(DataTools.extractLimitOne(listArtists, "name"));
}).catch((error) => {
resolve([">> ERROR 1 <<"]);
})
}).catch((error) => {
resolve([">> ERROR 2 <<"]);
});
});
} }
ngOnInit() { ngOnInit() {
const self = this;
this.getArtistsString = (id: number) => { return self.getArtistsStringCallback(id); }; this.getArtistsString = (id: number) => { return self.getArtistsStringCallback(id); };
this.countTrack = (id: number) => { return self.countTrackCallback(id); }; this.countTrack = (id: number) => { return self.countTrackCallback(id); };
let self = this;
self.name = "All Albums"; self.name = "All Albums";
self.description = "View all albums (no specific artist)"; self.description = "View all albums (no specific artist)";
//console.log(`get parameter id: ${ this.idArtist}`); //console.log(`get parameter id: ${ this.idArtist}`);
this.albumService.getOrder() this.albumService.getOrder()
.then((response: NodeData[]) => { .then((response: Album[]) => {
//console.log(`>>>> get album : ${JSON.stringify(response)}`) //console.log(`>>>> get album : ${JSON.stringify(response)}`)
self.albums = response; self.albums = response;
self.albumsSave = [...response];
}).catch((response) => { }).catch((response) => {
self.albums = undefined; self.albums = undefined;
}); });
// TODO later: get all orfan tracks ... // TODO later: get all orfans tracks ...
/* /*
this.artistService.getTrack(this.idArtist) this.artistService.getTrack(this.idArtist)
.then((response: NodeData[]) => { .then((response: NodeData[]) => {
@@ -69,7 +86,12 @@
*/ */
} }
onSearch(value: string) {
console.log(`Search value: ${value}`);
this.albums = this.albumsSave.filter(element => {
return element.name.toLowerCase().includes(value.toLowerCase());;
})
}
onSelectAlbum(event: any, idSelected: number): void { onSelectAlbum(event: any, idSelected: number): void {
if (event.ctrlKey) { if (event.ctrlKey) {
@@ -86,11 +108,11 @@
this.arianeService.navigateTrack({ trackId: idSelected, newWindows: event.which === 2 }); this.arianeService.navigateTrack({ trackId: idSelected, newWindows: event.which === 2 });
} }
} }
playAll(event: any):void { playAll(): void {
this.playerService.clear(); this.playerService.clear();
let self = this; let self = this;
this.trackService.getData() this.trackService.gets()
.then((response: NodeData[]) => { .then((response: Track[]) => {
let ids = []; let ids = [];
response.forEach(element => { response.forEach(element => {
ids.push(element.id); ids.push(element.id);
@@ -101,11 +123,11 @@
console.log(`error to get list o ftrack ...`) console.log(`error to get list o ftrack ...`)
}); });
} }
playShuffe(event: any):void { playShuffle(): void {
this.playerService.clear(); this.playerService.clear();
let self = this; let self = this;
this.trackService.getData() this.trackService.gets()
.then((response: NodeData[]) => { .then((response: Track[]) => {
let ids = []; let ids = [];
response.forEach(element => { response.forEach(element => {
ids.push(element.id); ids.push(element.id);
@@ -118,4 +140,3 @@
} }
} }

View File

@@ -2,21 +2,26 @@
<div class="title"> <div class="title">
Edit artist Edit artist
</div> </div>
<div class="fill-all" *ngIf="itemIsRemoved"> @if(itemIsRemoved) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
The artist has been removed The artist has been removed
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="itemIsNotFound"> }
@else if (itemIsNotFound) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
The artist does not exist The artist does not exist
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="itemIsLoading"> }
@else if (itemIsLoading) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
Loading ...<br/> Loading ...<br/>
@@ -24,18 +29,9 @@
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> }
<div class="request_raw"> @else {
<div class="label"> <div class="fill-all">
Type:
</div>
<div class="input">
<select [ngModel]="typeId"
(ngModelChange)="onChangeType($event)">
<option *ngFor="let element of listType" [ngValue]="element.value">{{element.label}}</option>
</select>
</div>
</div>
<div class="request_raw"> <div class="request_raw">
<div class="label"> <div class="label">
Name: Name:
@@ -66,10 +62,10 @@
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<!-- ------------------------- Cover section --------------------------------- --> <!-- ------------------------- Cover section --------------------------------- -->
<div class="title" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="title">
Covers Covers
</div> </div>
<div class="fill-all" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="fill-all">
<div class="hide-element"> <div class="hide-element">
<input type="file" <input type="file"
#fileInput #fileInput
@@ -79,7 +75,8 @@
</div> </div>
<div class="request_raw"> <div class="request_raw">
<div class="input"> <div class="input">
<div class="cover" *ngFor="let element of coversDisplay"> @for (element of coversDisplay; track element.id;) {
<div class="cover">
<div class="cover-image"> <div class="cover-image">
<img src="{{element.url}}"/> <img src="{{element.url}}"/>
</div> </div>
@@ -89,6 +86,7 @@
</button> </button>
</div> </div>
</div> </div>
}
<div class="cover"> <div class="cover">
<div class="cover-no-image"> <div class="cover-no-image">
</div> </div>
@@ -103,10 +101,10 @@
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<!-- ------------------------- ADMIN section --------------------------------- --> <!-- ------------------------- ADMIN section --------------------------------- -->
<div class="title" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="title">
Administration Administration
</div> </div>
<div class="fill-all" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="fill-all">
<div class="request_raw"> <div class="request_raw">
<div class="label"> <div class="label">
<i class="material-icons">data_usage</i> ID: <i class="material-icons">data_usage</i> ID:
@@ -138,17 +136,22 @@
<div class="label"> <div class="label">
<i class="material-icons">delete_forever</i> Trash: <i class="material-icons">delete_forever</i> Trash:
</div> </div>
<div class="input" *ngIf="(trackCount == '0' && albumsCount == '0')"> @if(trackCount == '0' && albumsCount == '0') {
<div class="input">
<button class="button color-button-cancel color-shadow-black" (click)="removeItem()" type="submit"> <button class="button color-button-cancel color-shadow-black" (click)="removeItem()" type="submit">
<i class="material-icons">delete</i> Remove Artist <i class="material-icons">delete</i> Remove Artist
</button> </button>
</div> </div>
<div class="input" *ngIf="(trackCount != '0' || albumsCount != '0')"> }
@else {
<div class="input">
<i class="material-icons">new_releases</i> Can not remove album or track depending on it <i class="material-icons">new_releases</i> Can not remove album or track depending on it
</div> </div>
}
</div> </div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
}
</div> </div>
<upload-progress [mediaTitle]="upload.labelMediaTitle" <upload-progress [mediaTitle]="upload.labelMediaTitle"

View File

@@ -5,10 +5,10 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { PopInService, UploadProgress } from '@kangaroo-and-rabbit/kar-cw';
import { Artist, Track } from 'app/back-api';
import { ArtistService, DataService, GenderService, ArianeService } from 'app/service'; import { ArtistService, DataService, GenderService, ArianeService, TrackService } from 'app/service';
import { UploadProgress } from 'common/popin/upload-progress/upload-progress';
import { PopInService } from 'common/service';
export class ElementList { export class ElementList {
constructor( constructor(
@@ -31,7 +31,6 @@ export class ArtistEditScene implements OnInit {
error: string = ''; error: string = '';
typeId: number = null;
name: string = ''; name: string = '';
description: string = ''; description: string = '';
coverFile: File; coverFile: File;
@@ -45,15 +44,10 @@ export class ArtistEditScene implements OnInit {
// section tha define the upload value to display in the pop-in of upload // section tha define the upload value to display in the pop-in of upload
public upload: UploadProgress = new UploadProgress(); public upload: UploadProgress = new UploadProgress();
listType: ElementList[] = [
{ value: undefined, label: '---' },
];
// --------------- confirm section ------------------ // --------------- confirm section ------------------
public confirmDeleteComment: string = null; public confirmDeleteComment: string = null;
public confirmDeleteImageUrl: string = null; public confirmDeleteImageUrl: string = null;
private deleteCoverId: number = null; private deleteCoverId: string = null;
private deleteItemId: number = null; private deleteItemId: number = null;
deleteConfirmed() { deleteConfirmed() {
if (this.deleteCoverId !== null) { if (this.deleteCoverId !== null) {
@@ -74,8 +68,9 @@ export class ArtistEditScene implements OnInit {
constructor(private dataService: DataService, constructor(private dataService: DataService,
private typeService: GenderService, private genderService: GenderService,
private artistService: ArtistService, private artistService: ArtistService,
private trackService: TrackService,
private arianeService: ArianeService, private arianeService: ArianeService,
private popInService: PopInService) { private popInService: PopInService) {
@@ -84,22 +79,11 @@ export class ArtistEditScene implements OnInit {
ngOnInit() { ngOnInit() {
this.idArtist = this.arianeService.getArtistId(); this.idArtist = this.arianeService.getArtistId();
let self = this; let self = this;
this.listType = [{ value: null, label: '---' }];
this.typeService.getData()
.then((response2) => {
for (let iii = 0; iii < response2.length; iii++) {
self.listType.push({ value: response2[iii].id, label: response2[iii].name });
}
}).catch((response2) => {
console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`);
});
this.artistService.get(this.idArtist) this.artistService.get(this.idArtist)
.then((response) => { .then((response: Artist) => {
// console.log("get response of track : " + JSON.stringify(response, null, 2)); // console.log("get response of track : " + JSON.stringify(response, null, 2));
self.name = response.name; self.name = response.name;
self.typeId = response.parentId;
self.description = response.description; self.description = response.description;
self.updateCoverList(response.covers); self.updateCoverList(response.covers);
// console.log("covers_list : " + JSON.stringify(self.covers_display, null, 2)); // console.log("covers_list : " + JSON.stringify(self.covers_display, null, 2));
@@ -113,14 +97,14 @@ export class ArtistEditScene implements OnInit {
self.itemIsLoading = false; self.itemIsLoading = false;
}); });
console.log(`get parameter id: ${this.idArtist}`); console.log(`get parameter id: ${this.idArtist}`);
this.artistService.getAlbum(this.idArtist) this.trackService.getAlbumIdsOfAnArtist(this.idArtist)
.then((response) => { .then((response: number[]) => {
self.albumsCount = "" + response.length; self.albumsCount = "" + response.length;
}).catch((response) => { }).catch((response) => {
self.albumsCount = '---'; self.albumsCount = '---';
}); });
this.artistService.getAllTracks(this.idArtist) this.trackService.getTracksOfAnArtist(this.idArtist)
.then((response) => { .then((response: Track[]) => {
self.trackCount = "" + response.length; self.trackCount = "" + response.length;
}).catch((response) => { }).catch((response) => {
self.trackCount = '---'; self.trackCount = '---';
@@ -133,7 +117,7 @@ export class ArtistEditScene implements OnInit {
for (let iii = 0; iii < covers.length; iii++) { for (let iii = 0; iii < covers.length; iii++) {
this.coversDisplay.push({ this.coversDisplay.push({
id: covers[iii], id: covers[iii],
url: this.dataService.getCoverThumbnailUrl(covers[iii]) url: this.dataService.getThumbnailUrl(covers[iii])
}); });
} }
} else { } else {
@@ -149,18 +133,9 @@ export class ArtistEditScene implements OnInit {
this.description = value; this.description = value;
} }
onChangeType(value: any): void {
console.log(`Change requested of type ... ${value}`);
this.typeId = value;
if (this.typeId === undefined) {
this.typeId = null;
}
}
sendValues(): void { sendValues(): void {
console.log('send new values....'); console.log('send new values....');
let data = { let data = {
parentId: this.typeId,
name: this.name, name: this.name,
description: this.description description: this.description
}; };
@@ -203,7 +178,7 @@ export class ArtistEditScene implements OnInit {
this.upload.clear(); this.upload.clear();
// display the upload pop-in // display the upload pop-in
this.popInService.open('popin-upload-progress'); this.popInService.open('popin-upload-progress');
this.artistService.uploadCover(file, this.idArtist, (count, total) => { this.artistService.uploadCover(this.idArtist, file, (count, total) => {
self.upload.mediaSendSize = count; self.upload.mediaSendSize = count;
self.upload.mediaSize = total; self.upload.mediaSize = total;
}) })
@@ -216,14 +191,14 @@ export class ArtistEditScene implements OnInit {
console.log('Can not add the cover in the track...'); console.log('Can not add the cover in the track...');
}); });
} }
removeCover(id: number) { removeCover(id: string) {
this.cleanConfirm(); this.cleanConfirm();
this.confirmDeleteComment = `Delete the cover ID: ${id}`; this.confirmDeleteComment = `Delete the cover ID: ${id}`;
this.confirmDeleteImageUrl = this.dataService.getCoverThumbnailUrl(id); this.confirmDeleteImageUrl = this.dataService.getThumbnailUrl(id);
this.deleteCoverId = id; this.deleteCoverId = id;
this.popInService.open('popin-delete-confirm'); this.popInService.open('popin-delete-confirm');
} }
removeCoverAfterConfirm(id: number) { removeCoverAfterConfirm(id: string) {
console.log(`Request remove cover: ${id}`); console.log(`Request remove cover: ${id}`);
let self = this; let self = this;
this.artistService.deleteCover(this.idArtist, id) this.artistService.deleteCover(this.idArtist, id)

View File

@@ -1,38 +1,25 @@
<div class="generic-page"> <div class="generic-page">
<div class="fill-title colomn_mutiple"> <description-area
<div class="cover-area"> [title]="name"
<div class="cover" *ngIf="covers" > [name]="albumName"
<img src="{{covers[0]}}"/> [description]="albumDescription"
</div> [cover1]="artistCovers"
</div> [cover2]="albumCovers"
<div [className]="covers ? 'description-area description-area-cover' : 'description-area description-area-no-cover'"> (play)="playAll()"
<div class="title"> (shuffle)="playShuffle()"/>
{{name}} @if(tracks) {
</div> <div class="fill-content colomn_single">
<div class="title">
{{albumName}}
</div>
<div class="description" *ngIf="albumDescription">
{{albumDescription}}
</div>
<div class="clear"></div> <div class="clear"></div>
<button class="button color-button color-shadow-black" (click)="playAll($event)" type="submit"> <div class="title">Track{{tracks.length > 1?"s":""}}:</div>
<i class="material-icons">play_arrow</i> Play All @for (data of tracks; track data.id;) {
</button>
<button class="button color-button color-shadow-black" style="margin-left:10px;" (click)="playShuffe($event)" type="submit">
<i class="material-icons">shuffle</i> Shuffle
</button>
</div>
</div>
<div class="fill-content colomn_mutiple" *ngIf="tracks">
<div class="clear"></div>
<div class="title" *ngIf="tracks.length > 1">Tracks:</div>
<div class="title" *ngIf="tracks.length == 1">Track:</div>
<app-element-track <app-element-track
*ngFor="let data of tracks"
[element]="data" [element]="data"
(click)="onSelectTrack($event, data.id)" (click)="onSelectTrack($event, data.id)"
(auxclick)="onSelectTrack($event, data.id)"></app-element-track> (auxclick)="onSelectTrack($event, data.id)"></app-element-track>
} @empty {
Aucune piste accessible.
}
</div> </div>
}
<div class="clear-end"></div> <div class="clear-end"></div>
</div> </div>

View File

@@ -5,7 +5,7 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Media } from 'app/model'; import { Track } from 'app/back-api';
import { ArtistService, DataService, ArianeService, AlbumService, TrackService, PlayerService } from 'app/service'; import { ArtistService, DataService, ArianeService, AlbumService, TrackService, PlayerService } from 'app/service';
@@ -19,13 +19,13 @@ export class ArtistAlbumScene implements OnInit {
public idAlbum = -1; public idAlbum = -1;
public name: string = ''; public name: string = '';
public description: string = undefined; public description: string = undefined;
public covers: Array<string> = undefined; public artistCovers: Array<string> = undefined;
public albumName: string = ''; public albumName: string = '';
public albumDescription: string = undefined; public albumDescription: string = undefined;
public albumCovers: string[] = undefined; public albumCovers: string[] = undefined;
public tracksIds: number[] = undefined; public tracksIds: number[] = undefined;
public tracks: Media[] = undefined; public tracks: Track[] = undefined;
constructor( constructor(
private artistService: ArtistService, private artistService: ArtistService,
@@ -38,8 +38,6 @@ export class ArtistAlbumScene implements OnInit {
} }
ngOnInit() { ngOnInit() {
// this.idPlaylist = parseInt(this.route.snapshot.paramMap.get('universId'));
// this.idType = parseInt(this.route.snapshot.paramMap.get('typeId'));
this.idArtist = this.arianeService.getArtistId(); this.idArtist = this.arianeService.getArtistId();
this.idAlbum = this.arianeService.getAlbumId(); this.idAlbum = this.arianeService.getAlbumId();
let self = this; let self = this;
@@ -47,18 +45,18 @@ export class ArtistAlbumScene implements OnInit {
.then((response) => { .then((response) => {
self.name = response.name; self.name = response.name;
self.description = response.description; self.description = response.description;
self.covers = this.dataService.getCoverListUrl(response.covers); self.artistCovers = this.dataService.getListUrl(response.covers);
}).catch((response) => { }).catch((response) => {
self.description = undefined; self.description = undefined;
self.name = '???'; self.name = '???';
self.covers = undefined; self.artistCovers = undefined;
// no check just ==> an error occured on album // no check just ==> an error occured on album
}); });
this.albumService.get(this.idAlbum) this.albumService.get(this.idAlbum)
.then((response) => { .then((response) => {
self.albumName = response.name; self.albumName = response.name;
self.albumDescription = response.description; self.albumDescription = response.description;
self.albumCovers = this.dataService.getCoverListUrl(response.covers); self.albumCovers = this.dataService.getListUrl(response.covers);
}).catch((response) => { }).catch((response) => {
self.albumDescription = undefined; self.albumDescription = undefined;
self.albumName = '???'; self.albumName = '???';
@@ -67,8 +65,8 @@ export class ArtistAlbumScene implements OnInit {
}); });
//console.log("all the tracks: " + self.tracksIds); //console.log("all the tracks: " + self.tracksIds);
this.trackService.getWithAlbum(self.idAlbum) this.trackService.getTracksWithAlbumId(self.idAlbum)
.then((response2: Media[]) => { .then((response2: Track[]) => {
self.tracks = response2; self.tracks = response2;
//console.log(`>>>>BBB get tracks : ${JSON.stringify(response2, null, 2)}`); //console.log(`>>>>BBB get tracks : ${JSON.stringify(response2, null, 2)}`);
}).catch((response) => { }).catch((response) => {
@@ -99,7 +97,7 @@ export class ArtistAlbumScene implements OnInit {
this.arianeService.navigateTrackEdit({ id: idSelected, newWindows: event.which === 2 }); this.arianeService.navigateTrackEdit({ id: idSelected, newWindows: event.which === 2 });
} }
} }
playAll(event: any):void { playAll(): void {
let elements: number[] = []; let elements: number[] = [];
for (let iii = 0; iii < this.tracks.length; iii++) { for (let iii = 0; iii < this.tracks.length; iii++) {
elements.push(this.tracks[iii].id); elements.push(this.tracks[iii].id);
@@ -107,7 +105,7 @@ export class ArtistAlbumScene implements OnInit {
this.playerService.clear(); this.playerService.clear();
this.playerService.setNewPlaylist(elements); this.playerService.setNewPlaylist(elements);
} }
playShuffe(event: any):void { playShuffle(): void {
let elements: number[] = []; let elements: number[] = [];
for (let iii = 0; iii < this.tracks.length; iii++) { for (let iii = 0; iii < this.tracks.length; iii++) {
elements.push(this.tracks[iii].id); elements.push(this.tracks[iii].id);

View File

@@ -1,46 +1,37 @@
<div class="generic-page"> <div class="generic-page">
<div class="fill-title colomn_mutiple"> <description-area
<div class="cover-area"> [title]="name"
<div class="cover" *ngIf="covers" > [description]="description"
<img src="{{covers[0]}}"/> [cover1]="covers"
</div> (play)="playAll()"
</div> (shuffle)="playShuffle()"/>
<div [className]="covers ? 'description-area description-area-cover' : 'description-area description-area-no-cover'"> @if(albums) {
<div class="title"> <div class="fill-content colomn_single">
{{name}}
</div>
<div class="description" *ngIf="description">
{{description}}
</div>
<button class="button color-button color-shadow-black" (click)="playAll($event)" type="submit">
<i class="material-icons">play_arrow</i> Play All
</button>
<button class="button color-button color-shadow-black" style="margin-left:10px;" (click)="playShuffe($event)" type="submit">
<i class="material-icons">shuffle</i> Shuffle
</button>
</div>
</div>
<div class="fill-content colomn_mutiple" *ngIf="albums">
<div class="clear"></div> <div class="clear"></div>
<div class="title" *ngIf="albums.length > 1">Albums:</div> <div class="title">Album{{albums.length > 1?"s":""}}:</div>
<div class="title" *ngIf="albums.length == 1">Album:</div> @for (data of albums; track data.id;) {
<div *ngFor="let data of albums" class="item-list" (click)="onSelectAlbum($event, data.id)" (auxclick)="onSelectAlbum($event, data.id)"> <div class="item-list" (click)="onSelectAlbum($event, data.id)" (auxclick)="onSelectAlbum($event, data.id)">
<app-element-season <app-element-season
[element]="data" [element]="data"
countSubType="Track" countSubType="Track"
[countSubTypeCallBack]="countTrack" [countSubTypeCallBack]="countTrack"
></app-element-season> ></app-element-season>
</div> </div>
}
</div> </div>
<div class="fill-content colomn_mutiple" *ngIf="tracks"> }
@if(tracks) {
<div class="fill-content colomn_mutiple">
<div class="clear"></div> <div class="clear"></div>
<div class="title" *ngIf="tracks.length > 1">Tracks:</div> <div class="title">Track{{tracks.length > 1?"s":""}}:</div>
<div class="title" *ngIf="tracks.length == 1">Track:</div> @for (data of tracks; track data.id;) {
<div *ngFor="let data of tracks" class="item item-video" (click)="onSelectTrack($event, data.id)" (auxclick)="onSelectTrack($event, data.id)"> <div class="item item-video" (click)="onSelectTrack($event, data.id)" (auxclick)="onSelectTrack($event, data.id)">
<app-element-video <app-element-video
[element]="data" [element]="data"
></app-element-video> ></app-element-video>
</div> </div>
}
</div> </div>
}
<div class="clear-end"></div> <div class="clear-end"></div>
</div> </div>

View File

@@ -5,9 +5,9 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Album, Track } from 'app/back-api';
import { ArtistService, DataService, ArianeService, AlbumService, PlayerService } from 'app/service'; import { ArtistService, DataService, ArianeService, AlbumService, PlayerService, TrackService } from 'app/service';
import { NodeData } from 'common/model';
@Component({ @Component({
selector: 'app-artist', selector: 'app-artist',
@@ -19,8 +19,8 @@ export class ArtistScene implements OnInit {
public name: string = ''; public name: string = '';
public description: string = undefined; public description: string = undefined;
public covers: string[] = undefined; public covers: string[] = undefined;
public albums: NodeData[] = undefined; public albums: Album[] = undefined;
public tracks: any[] = undefined; public tracks: Track[] = undefined;
public countSubElement: number = undefined; public countSubElement: number = undefined;
countTrack: (id: number) => Promise<Number>; countTrack: (id: number) => Promise<Number>;
@@ -28,13 +28,14 @@ export class ArtistScene implements OnInit {
private albumService: AlbumService, private albumService: AlbumService,
private artistService: ArtistService, private artistService: ArtistService,
private playerService: PlayerService, private playerService: PlayerService,
private trackService: TrackService,
private arianeService: ArianeService, private arianeService: ArianeService,
private dataService: DataService) { private dataService: DataService) {
} }
countTrackCallback(albumId: number): Promise<Number> { countTrackCallback(albumId: number): Promise<Number> {
return this.albumService.countTrack(albumId); return this.trackService.countTracksWithAlbumId(albumId);
} }
ngOnInit() { ngOnInit() {
@@ -43,25 +44,29 @@ export class ArtistScene implements OnInit {
// this.idType = parseInt(this.route.snapshot.paramMap.get('typeId')); // this.idType = parseInt(this.route.snapshot.paramMap.get('typeId'));
this.idArtist = this.arianeService.getArtistId(); this.idArtist = this.arianeService.getArtistId();
let self = this; let self = this;
this.artistService.get(this.idArtist) this.artistService.get(this.idArtist)
.then((response) => { .then((response) => {
self.name = response.name; self.name = response.name;
self.description = response.description; self.description = response.description;
self.covers = this.dataService.getCoverListUrl(response.covers); self.covers = this.dataService.getListUrl(response.covers);
}).catch((response) => { }).catch((response) => {
self.name = '???'; self.name = '???';
self.description = undefined; self.description = undefined;
self.covers = undefined; self.covers = undefined;
}); });
//console.log(`get parameter id: ${ this.idArtist}`); //console.log(`get parameter id: ${ this.idArtist}`);
this.artistService.getAlbum(this.idArtist) this.trackService.getAlbumIdsOfAnArtist(this.idArtist)
.then((response: NodeData[]) => { .then((albumIds: number[]) => {
this.albumService.getAll(albumIds)
.then((response: Album[]) => {
//console.log(`>>>> get album : ${JSON.stringify(response)}`) //console.log(`>>>> get album : ${JSON.stringify(response)}`)
self.albums = response; self.albums = response;
}).catch((response) => { }).catch((response) => {
self.albums = undefined; self.albums = undefined;
}); });
}).catch((response) => {
self.albums = undefined;
});
// TODO later: get all orfan tracks ... // TODO later: get all orfan tracks ...
/* /*
this.artistService.getTrack(this.idArtist) this.artistService.getTrack(this.idArtist)
@@ -97,10 +102,10 @@ export class ArtistScene implements OnInit {
for (let iii = 0; iii < this.albums.length; iii++) { for (let iii = 0; iii < this.albums.length; iii++) {
elements.push(this.albums[iii].id); elements.push(this.albums[iii].id);
} }
return this.albumService.getAllTracksForAlbums(elements); return this.trackService.getTracksIdsForAlbums(elements);
} }
playAll(event: any):void { playAll(): void {
this.playerService.clear(); this.playerService.clear();
let self = this; let self = this;
this.getAllTracksIds() this.getAllTracksIds()
@@ -111,7 +116,7 @@ export class ArtistScene implements OnInit {
console.log(`error to get list o ftrack ...`) console.log(`error to get list o ftrack ...`)
}); });
} }
playShuffe(event: any):void { playShuffle(): void {
this.playerService.clear(); this.playerService.clear();
let self = this; let self = this;
this.getAllTracksIds() this.getAllTracksIds()

View File

@@ -1,30 +1,16 @@
<div class="generic-page"> <div class="generic-page">
<div class="fill-title colomn_mutiple"> <description-area
<div class="cover-area"> [title]="name"
<div class="cover" *ngIf="covers" > [description]="description"
<img src="{{covers[0]}}"/> [cover1]="covers"
</div> (play)="playAll()"
</div> (shuffle)="playShuffle()"/>
<div [className]="covers ? 'description-area description-area-cover' : 'description-area description-area-no-cover'"> @if(artists) {
<div class="title"> <div class="fill-content colomn_single">
{{name}}
</div>
<div class="description" *ngIf="description">
{{description}}
</div>
<button class="button color-button color-shadow-black" (click)="playAll($event)" type="submit">
<i class="material-icons">play_arrow</i> Play All
</button>
<button class="button color-button color-shadow-black" style="margin-left:10px;" (click)="playShuffe($event)" type="submit">
<i class="material-icons">shuffle</i> Shuffle
</button>
</div>
</div>
<div class="fill-content colomn_mutiple" *ngIf="artists">
<div class="clear"></div> <div class="clear"></div>
<div class="title" *ngIf="artists.length > 1">Artists:</div> <div class="title">Artist{{artists.length > 1?"s":""}}: <app-entry placeholder="Search..." (changeValue)="onSearch($event)"></app-entry></div>
<div class="title" *ngIf="artists.length == 1">Artist:</div> @for (data of artists; track data.id;) {
<div *ngFor="let data of artists" class="item-list" (click)="onSelectArtist($event, data.id)" (auxclick)="onSelectArtist($event, data.id)"> <div class="item-list" (click)="onSelectArtist($event, data.id)" (auxclick)="onSelectArtist($event, data.id)">
<app-element-season <app-element-season
[element]="data" [element]="data"
countSubType="Album" countSubType="Album"
@@ -33,6 +19,8 @@
[countSubType2CallBack]="countTrack" [countSubType2CallBack]="countTrack"
></app-element-season> ></app-element-season>
</div> </div>
}
</div> </div>
}
<div class="clear-end"></div> <div class="clear-end"></div>
</div> </div>

View File

@@ -5,9 +5,9 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Artist, Track } from 'app/back-api';
import { ArtistService, ArianeService, AlbumService, TrackService, PlayerService } from 'app/service'; import { ArtistService, ArianeService, TrackService, PlayerService } from 'app/service';
import { NodeData } from 'common/model';
@Component({ @Component({
selector: 'app-artists', selector: 'app-artists',
@@ -19,13 +19,13 @@ export class ArtistsScene implements OnInit {
covers: Array<string> = []; covers: Array<string> = [];
name: string = "Artists"; name: string = "Artists";
description: string = "All available artists"; description: string = "All available artists";
artists: NodeData[]; artists: Artist[];
artistsSave: Artist[];
countTrack: (id: number) => Promise<Number>; countTrack: (id: number) => Promise<Number>;
countAlbum: (id: number) => Promise<Number>; countAlbum: (id: number) => Promise<Number>;
constructor( constructor(
private artistService: ArtistService, private artistService: ArtistService,
private albumService: AlbumService,
private trackService: TrackService, private trackService: TrackService,
private playerService: PlayerService, private playerService: PlayerService,
private arianeService: ArianeService) { private arianeService: ArianeService) {
@@ -36,16 +36,23 @@ export class ArtistsScene implements OnInit {
let self = this; let self = this;
this.countTrack = (id: number) => { return self.countTrackCallback(id); }; this.countTrack = (id: number) => { return self.countTrackCallback(id); };
this.countAlbum = (id: number) => { return self.countAlbumCallback(id); }; this.countAlbum = (id: number) => { return self.countAlbumCallback(id); };
// this.idPlaylist = parseInt(this.route.snapshot.paramMap.get('universId'));
// this.idType = parseInt(this.route.snapshot.paramMap.get('typeId'));
this.artistService.getOrder() this.artistService.getOrder()
.then((response: NodeData[]) => { .then((response: Artist[]) => {
self.artists = response; self.artists = response;
self.artistsSave = [...response];
//console.log("get artists: " + JSON.stringify(self.artists)); //console.log("get artists: " + JSON.stringify(self.artists));
}).catch((response) => { }).catch((response) => {
self.artists = undefined; self.artists = undefined;
}); });
} }
onSearch(value: string) {
console.log(`Search value: ${value}`);
this.artists = this.artistsSave.filter(element => {
return element.name.toLowerCase().includes(value.toLowerCase());;
})
}
onSelectArtist(event: any, idSelected: number): void { onSelectArtist(event: any, idSelected: number): void {
if (event.ctrlKey) { if (event.ctrlKey) {
this.arianeService.navigateArtistEdit({ id: idSelected, newWindows: event.which === 2 }); this.arianeService.navigateArtistEdit({ id: idSelected, newWindows: event.which === 2 });
@@ -55,16 +62,16 @@ export class ArtistsScene implements OnInit {
} }
countTrackCallback(artistId: number): Promise<Number> { countTrackCallback(artistId: number): Promise<Number> {
return this.artistService.countTrack(artistId); return this.trackService.countTracksOfAnArtist(artistId);
} }
countAlbumCallback(artistId: number): Promise<Number> { countAlbumCallback(artistId: number): Promise<Number> {
return this.artistService.countAlbum(artistId); return this.trackService.countAlbumOfAnArtist(artistId);
} }
playAll(event: any):void { playAll(): void {
this.playerService.clear(); this.playerService.clear();
let self = this; let self = this;
this.trackService.getData() this.trackService.gets()
.then((response: NodeData[]) => { .then((response: Track[]) => {
let ids = []; let ids = [];
response.forEach(element => { response.forEach(element => {
ids.push(element.id); ids.push(element.id);
@@ -75,11 +82,11 @@ export class ArtistsScene implements OnInit {
console.log(`error to get list o ftrack ...`) console.log(`error to get list o ftrack ...`)
}); });
} }
playShuffe(event: any):void { playShuffle(): void {
this.playerService.clear(); this.playerService.clear();
let self = this; let self = this;
this.trackService.getData() this.trackService.gets()
.then((response: NodeData[]) => { .then((response: Track[]) => {
let ids = []; let ids = [];
response.forEach(element => { response.forEach(element => {
ids.push(element.id); ids.push(element.id);
@@ -87,7 +94,7 @@ export class ArtistsScene implements OnInit {
self.playerService.setNewPlaylistShuffle(ids); self.playerService.setNewPlaylistShuffle(ids);
}) })
.catch(() => { .catch(() => {
console.log(`error to get list o ftrack ...`) console.log(`error to get list o track ...`)
}); });
} }
} }

View File

@@ -5,7 +5,6 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ArianeService } from '../../service/ariane';
@Component({ @Component({
selector: 'app-error-viewer', selector: 'app-error-viewer',
@@ -13,7 +12,7 @@ import { ArianeService } from '../../service/ariane';
styleUrls: ['./error-viewer.less'] styleUrls: ['./error-viewer.less']
}) })
export class ErrorViewerScene implements OnInit { export class ErrorViewerScene implements OnInit {
constructor(private arianeService: ArianeService) { } constructor() { }
ngOnInit() { ngOnInit() {
} }

View File

@@ -1,30 +1,38 @@
<div class="generic-page"> <div class="generic-page">
<div class="fill-title colomn_mutiple"> <div class="fill-title colomn_mutiple">
<div class="cover-area"> <div class="cover-area">
<div class="cover" *ngIf="cover != null" > @if (cover != null) {
<div class="cover">
<img src="{{cover}}"/> <img src="{{cover}}"/>
</div> </div>
}
</div> </div>
<div [className]="cover != null ? 'description-area description-area-cover' : 'description-area description-area-no-cover'"> <div [className]="cover != null ? 'description-area description-area-cover' : 'description-area description-area-no-cover'">
<div class="title"> <div class="title">
{{name}} {{name}}
</div> </div>
<div class="description" *ngIf="description"> @if(description) {
<div class="description">
{{description}} {{description}}
</div> </div>
}
</div> </div>
</div> </div>
<div class="fill-content colomn_mutiple"> <div class="fill-content colomn_mutiple">
<div class="clear"></div> <div class="clear"></div>
<div *ngFor="let data of artists" class="item" (click)="onSelectArtist($event, data.id)" (auxclick)="onSelectArtist($event, data.id)"> @for (data of artists; track data.id;) {
<app-element-artist [element]="data"></app-element-artist> <div class="item" (click)="onSelectArtist($event, data.id)" (auxclick)="onSelectArtist($event, data.id)">
<!--<app-element-artist [element]="data"/>-->
</div> </div>
}
</div> </div>
<div class="fill-content colomn_mutiple"> <div class="fill-content colomn_mutiple">
<div class="clear"></div> <div class="clear"></div>
<div *ngFor="let data of tracks" class="item item-track" (click)="onSelectMedia($event, data.id)" (auxclick)="onSelectMedia($event, data.id)"> @for (data of tracks; track data.id;) {
<app-element-track [element]="data"></app-element-track> <div class="item item-track" (click)="onSelectTrack($event, data.id)" (auxclick)="onSelectTrack($event, data.id)">
<app-element-track [element]="data"/>
</div> </div>
}
</div> </div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>

View File

@@ -6,7 +6,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { GenderService, DataService, ArianeService } from 'app/service'; import { GenderService, DataService, ArianeService, TrackService } from 'app/service';
@Component({ @Component({
selector: 'app-gender', selector: 'app-gender',
@@ -26,6 +26,7 @@ export class GenderScene implements OnInit {
tracks = []; tracks = [];
constructor( constructor(
private genderService: GenderService, private genderService: GenderService,
private trackService: TrackService,
private arianeService: ArianeService, private arianeService: ArianeService,
private dataService: DataService) { private dataService: DataService) {
//NOTHING TO DO ... //NOTHING TO DO ...
@@ -44,9 +45,9 @@ export class GenderScene implements OnInit {
self.cover = null; self.cover = null;
self.covers = []; self.covers = [];
} else { } else {
self.cover = self.dataService.getCoverUrl(response.covers[0]); self.cover = self.dataService.getUrl(response.covers[0]);
for (let iii = 0; iii < response.covers.length; iii++) { for (let iii = 0; iii < response.covers.length; iii++) {
self.covers.push(self.dataService.getCoverUrl(response.covers[iii])); self.covers.push(self.dataService.getUrl(response.covers[iii]));
} }
} }
}).catch((response) => { }).catch((response) => {
@@ -55,7 +56,9 @@ export class GenderScene implements OnInit {
self.covers = []; self.covers = [];
self.cover = null; self.cover = null;
}); });
this.genderService.getSubArtist(this.genderId) /*
TODO ???
this.trackService.getSubArtist(this.genderId)
.then((response) => { .then((response) => {
console.log(` ==> get answer sub-artist: ${JSON.stringify(response)}`); console.log(` ==> get answer sub-artist: ${JSON.stringify(response)}`);
self.artistsError = ''; self.artistsError = '';
@@ -65,7 +68,8 @@ export class GenderScene implements OnInit {
self.artistsError = 'Wrong e-mail/login or password'; self.artistsError = 'Wrong e-mail/login or password';
self.artists = []; self.artists = [];
}); });
this.genderService.getSubTrack(this.genderId) */
this.trackService.getTracksForGender(this.genderId)
.then((response) => { .then((response) => {
console.log(` ==> get answer sub-track: ${JSON.stringify(response)}`); console.log(` ==> get answer sub-track: ${JSON.stringify(response)}`);
self.tracksError = ''; self.tracksError = '';

View File

@@ -3,9 +3,11 @@
Karusic Karusic
</div> </div>
<div class="fill-all colomn_mutiple"> <div class="fill-all colomn_mutiple">
<div *ngFor="let data of dataList" class="item-home" (click)="onSelectType($event, data.id)" (auxclick)="onSelectType($event, data.id)"> @for (data of dataList; track data.id) {
<app-element-type [element]="data"></app-element-type> <div class="item-home" (click)="onSelectType($event, data.id)" (auxclick)="onSelectType($event, data.id)">
<app-element-type [element]="data"/>
</div> </div>
}
<div class="clear"></div> <div class="clear"></div>
</div> </div>
</div> </div>

View File

@@ -1,8 +1,10 @@
<div class="generic-page"> <div class="generic-page">
<div class="fill-all colomn_mutiple"> <div class="fill-all colomn_mutiple">
<div *ngFor="let data of tracks" class="item item-track" (click)="onSelectTrack($event, data)" (auxclick)="onSelectTrack($event, data)"> @for (data of tracks; track data.id) {
<div class="item item-track" (click)="onSelectTrack($event, data)" (auxclick)="onSelectTrack($event, data)">
<app-element-track [element]="data"></app-element-track> <app-element-track [element]="data"></app-element-track>
</div> </div>
}
<div class="clear"></div> <div class="clear"></div>
</div> </div>
</div> </div>

View File

@@ -2,21 +2,26 @@
<div class="title"> <div class="title">
Edit Media Edit Media
</div> </div>
<div class="fill-all" *ngIf="itemIsRemoved"> @if(itemIsRemoved) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
The media has been removed The media has been removed
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="itemIsNotFound"> }
@else if (itemIsNotFound) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
The media does not exist The media does not exist
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="itemIsLoading"> }
@else if (itemIsLoading) {
<div class="fill-all">
<div class="message-big"> <div class="message-big">
<br/><br/><br/> <br/><br/><br/>
Loading ...<br/> Loading ...<br/>
@@ -24,8 +29,9 @@
<br/><br/><br/> <br/><br/><br/>
</div> </div>
</div> </div>
}
<div class="fill-all" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> @else {
<div class="fill-all">
<div class="request_raw"> <div class="request_raw">
<div class="label"> <div class="label">
Title: Title:
@@ -57,7 +63,9 @@
<div class="input"> <div class="input">
<select [ngModel]="data.genderId" <select [ngModel]="data.genderId"
(ngModelChange)="onChangeGender($event)"> (ngModelChange)="onChangeGender($event)">
<option *ngFor="let element of listGender" [ngValue]="element.value">{{element.label}}</option> @for (element of listGender; track element.value;) {
<option [ngValue]="element.value">{{element.label}}</option>
}
</select> </select>
</div> </div>
<div class="input_add"> <div class="input_add">
@@ -73,7 +81,9 @@
<div class="input"> <div class="input">
<select [ngModel]="data.artistId" <select [ngModel]="data.artistId"
(ngModelChange)="onChangeArtist($event)"> (ngModelChange)="onChangeArtist($event)">
<option *ngFor="let element of listArtist" [ngValue]="element.value">{{element.label}}</option> @for (element of listArtist; track element.value;) {
<option [ngValue]="element.value">{{element.label}}</option>
}
</select> </select>
</div> </div>
<div class="input_add"> <div class="input_add">
@@ -89,7 +99,9 @@
<div class="input"> <div class="input">
<select [ngModel]="data.albumId" <select [ngModel]="data.albumId"
(ngModelChange)="onChangeAlbum($event)"> (ngModelChange)="onChangeAlbum($event)">
<option *ngFor="let element of listAlbum" [ngValue]="element.value">{{element.label}}</option> @for (element of listAlbum; track element.value;) {
<option [ngValue]="element.value">{{element.label}}</option>
}
</select> </select>
</div> </div>
<div class="input_add"> <div class="input_add">
@@ -119,10 +131,10 @@
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<!-- ------------------------- ADMIN section --------------------------------- --> <!-- ------------------------- ADMIN section --------------------------------- -->
<div class="title" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="title">
Administration Administration
</div> </div>
<div class="fill-all" *ngIf="!itemIsRemoved && !itemIsNotFound && !itemIsLoading"> <div class="fill-all">
<div class="request_raw"> <div class="request_raw">
<div class="label"> <div class="label">
<i class="material-icons">data_usage</i> ID: <i class="material-icons">data_usage</i> ID:
@@ -144,6 +156,7 @@
</div> </div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
}
</div> </div>
<create-type ></create-type> <create-type ></create-type>

View File

@@ -5,13 +5,11 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { UploadProgress, PopInService, isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
import { Track } from 'app/back-api';
import { DataService, GenderService, ArtistService, TrackService, ArianeService, AlbumService } from 'app/service'; import { DataService, GenderService, ArtistService, TrackService, ArianeService, AlbumService } from 'app/service';
import { UploadProgress } from 'common/popin/upload-progress/upload-progress';
import { PopInService } from 'common/service';
import { Media } from 'app/model';
import { isNullOrUndefined } from 'common/utils';
export interface ElementList { export interface ElementList {
value?: number; value?: number;
@@ -25,7 +23,7 @@ class DataToSend {
track?: number; track?: number;
artistId: number = null; artistId: number = null;
albumId: number = null; albumId: number = null;
dataId: number = -1; dataId: string = "";
genderId: number = null; genderId: number = null;
generatedName: string = ''; generatedName: string = '';
clone() { clone() {
@@ -164,7 +162,7 @@ export class TrackEditScene implements OnInit {
console.log(`get response3 : ${JSON.stringify(response3, null, 2)}`); console.log(`get response3 : ${JSON.stringify(response3, null, 2)}`);
}); });
this.trackService.get(this.idTrack) this.trackService.get(this.idTrack)
.then((response: Media) => { .then((response: Track) => {
console.log(`get response of track : ${JSON.stringify(response, null, 2)}`); console.log(`get response of track : ${JSON.stringify(response, null, 2)}`);
self.data.name = response.name; self.data.name = response.name;
self.data.description = response.description; self.data.description = response.description;

View File

@@ -1,55 +1,73 @@
<div class="main-reduce"> <div class="main-reduce">
<div class="fill-all" *ngIf="mediaIsNotFound"> @if(mediaIsNotFound) {
<div class="fill-all">
<div class="title"> <div class="title">
Play media<br/><br/><br/><br/><br/> Play media<br/><br/><br/><br/><br/>
The media does not exist The media does not exist
</div> </div>
</div> </div>
<div class="fill-all" *ngIf="mediaIsLoading"> }
@if(mediaIsLoading) {
<div class="fill-all">
<div class="title"> <div class="title">
Play media<br/><br/><br/><br/><br/> Play media<br/><br/><br/><br/><br/>
Loading ...<br/> Loading ...<br/>
Please wait. Please wait.
</div> </div>
</div> </div>
}
<div class="fill-all" *ngIf="!mediaIsNotFound && !mediaIsLoading && !playTrack"> @if(!mediaIsNotFound && !mediaIsLoading && !playTrack) {
<div class="fill-all">
<div class="title"> <div class="title">
{{name}} {{name}}
</div> </div>
<div class="cover-full"> <div class="cover-full">
<div class="cover"> <div class="cover">
<div class="cover-image" *ngIf="covers"> @if (covers && covers.length > 0) {
<div class="cover-image">
<img src="{{covers[0]}}"/> <img src="{{covers[0]}}"/>
</div> </div>
<div class="cover-no-image" *ngIf="covers"></div> }
@else {
<div class="cover-no-image"></div>
}
<div class="cover-button"> <div class="cover-button">
<button (click)="onRequirePlay()"> <button (click)="onRequirePlay()">
<i class="material-icons big-button">play_circle_outline</i> <i class="material-icons big-button">play_circle_outline</i>
</button> </button>
</div> </div>
</div> </div>
<div class="cover-button-next" *ngIf="haveNext !== null"> @if (haveNext !== null) {
<div class="cover-button-next">
<button (click)="onRequireNext($event)" (auxclick)="onRequireNext($event)"> <button (click)="onRequireNext($event)" (auxclick)="onRequireNext($event)">
<i class="material-icons big-button">arrow_forward_ios</i> <i class="material-icons big-button">arrow_forward_ios</i>
</button> </button>
</div> </div>
<div class="cover-button-previous" *ngIf="havePrevious !== null"> }
@if (havePrevious !== null) {
<div class="cover-button-previous">
<button (click)="onRequirePrevious($event)" (auxclick)="onRequirePrevious($event)"> <button (click)="onRequirePrevious($event)" (auxclick)="onRequirePrevious($event)">
<i class="material-icons big-button">arrow_back_ios</i> <i class="material-icons big-button">arrow_back_ios</i>
</button> </button>
</div> </div>
}
</div> </div>
<div class="clear"></div> <div class="clear"></div>
<div class="episode" *ngIf="artistName!=null"> @if (artistName!=null) {
<div class="episode">
<b>Artist:</b> {{artistName}} <b>Artist:</b> {{artistName}}
</div> </div>
<div class="episode" *ngIf="albumName!=null"> }
@if (albumName!=null) {
<div class="episode">
<b>Album:</b> {{albumName}} <b>Album:</b> {{albumName}}
</div> </div>
<div class="episode" *ngIf="episode!=null"> }
<b>Episode:</b> {{episode}} @if (track!=null) {
<div class="episode">
<b>Piste:</b> {{track}}
</div> </div>
}
<div class="episode"> <div class="episode">
<b>generatedName:</b> {{generatedName}} <b>generatedName:</b> {{generatedName}}
</div> </div>
@@ -57,11 +75,13 @@
{{description}} {{description}}
</div> </div>
</div> </div>
<div class="fill-all bg-black" *ngIf="playTrack"> }
@if (playTrack) {
<div class="fill-all bg-black">
<div class="track" <div class="track"
#globalVideoElement #globalVideoElement
(mousemove)="startHideTimer()" (mousemove)="startHideTimer()"
(fullscreenchange)="onFullscreenChange($event)"> (fullscreenchange)="onFullscreenChange()">
<div class="track-elem"> <div class="track-elem">
<video src="{{trackSource}}" <video src="{{trackSource}}"
#trackPlayer #trackPlayer
@@ -78,9 +98,14 @@
<!--<p>Your browser does not support HTML5 track player. download track: <a href="{{trackSource}}>link here</a>.</p>--> <!--<p>Your browser does not support HTML5 track player. download track: <a href="{{trackSource}}>link here</a>.</p>-->
</video> </video>
</div> </div>
<div class="controls" *ngIf="!displayNeedHide || !isPlaying"> @if (!displayNeedHide || !isPlaying) {
<button (click)="onPlay()" *ngIf="!isPlaying" ><i class="material-icons">play_arrow</i></button> <div class="controls">
<button (click)="onPause()" *ngIf="isPlaying" ><i class="material-icons">pause</i></button> @if (!isPlaying) {
<button (click)="onPlay()"><i class="material-icons">play_arrow</i></button>
}
@else {
<button (click)="onPause()"><i class="material-icons">pause</i></button>
}
<button (click)="onStop()" ><i class="material-icons">stop</i></button> <button (click)="onStop()" ><i class="material-icons">stop</i></button>
<div class="timer"> <div class="timer">
<div> <div>
@@ -98,36 +123,50 @@
<button (click)="onForward()"><i class="material-icons">fast_forward</i></button> <button (click)="onForward()"><i class="material-icons">fast_forward</i></button>
<!--<button (click)="onNext()"><i class="material-icons">navigate_next</i></button>--> <!--<button (click)="onNext()"><i class="material-icons">navigate_next</i></button>-->
<!--<button (click)="onMore()" ><i class="material-icons">more_vert</i></button>--> <!--<button (click)="onMore()" ><i class="material-icons">more_vert</i></button>-->
<button (click)="onFullscreen()" *ngIf="!isFullScreen"><i class="material-icons">fullscreen</i></button> @if (!isFullScreen) {
<button (click)="onFullscreenExit()" *ngIf="isFullScreen"><i class="material-icons">fullscreen_exit</i></button> <button (click)="onFullscreen()"><i class="material-icons">fullscreen</i></button>
}
@else {
<button (click)="onFullscreenExit()"><i class="material-icons">fullscreen_exit</i></button>
}
<!--<button (click)="onTakeScreenShoot()"><i class="material-icons">add_a_photo</i></button>--> <!--<button (click)="onTakeScreenShoot()"><i class="material-icons">add_a_photo</i></button>-->
<button (click)="onVolumeMenu()" ><i class="material-icons">volume_up</i></button> <button (click)="onVolumeMenu()" ><i class="material-icons">volume_up</i></button>
@if (!isPlaying) {
<button class="bigPause" (click)="onPauseToggle()"><i *ngIf="!isPlaying" class="material-icons">play_circle_outline</i></button> <button class="bigPause" (click)="onPauseToggle()"><i class="material-icons">play_circle_outline</i></button>
<button class="bigRewind" (click)="onRewind()"><i *ngIf="!isPlaying" class="material-icons">fast_rewind</i></button> <button class="bigRewind" (click)="onRewind()"><i class="material-icons">fast_rewind</i></button>
<button class="bigForward" (click)="onForward()"><i *ngIf="!isPlaying" class="material-icons">fast_forward</i></button> <button class="bigForward" (click)="onForward()"><i class="material-icons">fast_forward</i></button>
}
</div> </div>
}
<div class="title-inline" *ngIf="!isFullScreen || !isPlaying"> @if(!isFullScreen || !isPlaying) {
<div class="title-inline">
{{generatedName}} {{generatedName}}
</div> </div>
<div class="track-button" *ngIf="!isFullScreen || !isPlaying"> <div class="track-button">
<button (click)="onRequireStop()"> <button (click)="onRequireStop()">
<i class="material-icons big-button">highlight_off</i> <i class="material-icons big-button">highlight_off</i>
</button> </button>
</div> </div>
<div class="volume" *ngIf="displayVolumeMenu && (!displayNeedHide || !isPlaying)"> }
@if (displayVolumeMenu && (!displayNeedHide || !isPlaying)) {
<div class="volume">
<div class="volume-menu"> <div class="volume-menu">
<div class="slidecontainer"> <div class="slidecontainer">
<input type="range" min="0" max="100" class="slider" <input type="range" min="0" max="100" class="slider"
[value]="volumeValue" [value]="volumeValue"
(input)="onVolume($event.target)"> (input)="onVolume($event.target)">
</div> </div>
<button (click)="onVolumeMute()" *ngIf="!trackPlayer.muted"><i class="material-icons">volume_mute</i></button> @if (!trackPlayer.muted) {
<button (click)="onVolumeUnMute()" *ngIf="trackPlayer.muted"><i class="material-icons">volume_off</i></button> <button (click)="onVolumeMute()"><i class="material-icons">volume_mute</i></button>
}
@else {
<button (click)="onVolumeUnMute()"><i class="material-icons">volume_off</i></button>
}
</div> </div>
</div> </div>
}
</div> </div>
</div> </div>
}
<canvas #canvascreenshoot style="overflow:auto"></canvas> <canvas #canvascreenshoot style="overflow:auto"></canvas>
</div> </div>

View File

@@ -5,9 +5,9 @@
*/ */
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core'; import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
import { Track } from 'app/back-api';
import { DataService, TrackService, ArtistService, AlbumService, ArianeService } from 'app/service'; import { DataService, TrackService, ArtistService, AlbumService, ArianeService } from 'app/service';
import { HttpWrapperService } from 'common/service';
import { isNullOrUndefined } from 'common/utils';
@Component({ @Component({
selector: 'app-track', selector: 'app-track',
@@ -47,14 +47,13 @@ export class TrackScene implements OnInit {
name: string = ''; name: string = '';
description: string = ''; description: string = '';
episode:number = undefined; track?: number;
artists:number[] = undefined; artists?: number[];
artistName:string = undefined; artistName?: string;
albumId:number = undefined; albumId?: number;
albumName:string = undefined; albumName?: string;
dataId:number = -1; dataId: string = "";
time:number = undefined; typeId?: number;
typeId:number = undefined;
generatedName: string = ''; generatedName: string = '';
trackSource: string = ''; trackSource: string = '';
covers: string[]; covers: string[];
@@ -75,7 +74,6 @@ export class TrackScene implements OnInit {
constructor(private trackService: TrackService, constructor(private trackService: TrackService,
private artistService: ArtistService, private artistService: ArtistService,
private albumService: AlbumService, private albumService: AlbumService,
private httpService: HttpWrapperService,
private arianeService: ArianeService, private arianeService: ArianeService,
private dataService: DataService) { private dataService: DataService) {
@@ -134,21 +132,18 @@ export class TrackScene implements OnInit {
this.generatedName = `${this.generatedName}s${this.albumName}-`; this.generatedName = `${this.generatedName}s${this.albumName}-`;
} }
} }
if(this.episode !== undefined) { if (this.track !== undefined) {
if(this.episode < 10) { if (this.track < 10) {
this.generatedName = `${this.generatedName }e0${ this.episode }-`; this.generatedName = `${this.generatedName}e0${this.track}-`;
} else { } else {
this.generatedName = `${this.generatedName }e${ this.episode }-`; this.generatedName = `${this.generatedName}e${this.track}-`;
} }
} }
this.generatedName = this.generatedName + this.name; this.generatedName = this.generatedName + this.name;
this.generatedName = this.generatedName.replace(new RegExp('&', 'g'), '_'); this.generatedName = this.generatedName.replace(new RegExp('&', 'g'), '_');
this.generatedName = this.generatedName.replace(new RegExp('/', 'g'), '_'); this.generatedName = this.generatedName.replace(new RegExp('/', 'g'), '_');
// update the path of the uri request // update the path of the uri request
this.trackSource = this.httpService.createRESTCall2({ this.trackSource = this.dataService.getUrl(this.dataId, this.generatedName);
api: `data/${ this.dataId}/${this.generatedName}`,
addURLToken: true,
});
} }
myPeriodicCheckFunction() { myPeriodicCheckFunction() {
@@ -201,26 +196,22 @@ export class TrackScene implements OnInit {
self.haveNext = null; self.haveNext = null;
self.havePrevious = null; self.havePrevious = null;
this.trackService.get(this.idTrack) this.trackService.get(this.idTrack)
.then((response) => { .then((response: Track) => {
console.log(`get response of track : ${JSON.stringify(response, null, 2)}`); console.log(`get response of track : ${JSON.stringify(response, null, 2)}`);
self.error = ''; self.error = '';
self.name = response.name; self.name = response.name;
self.description = response.description; self.description = response.description;
self.episode = response.episode; //self.episode = response.episode;
self.artists = response.artists; self.artists = response.artists;
self.albumId = response.albumId; self.albumId = response.albumId;
self.dataId = response.dataId; self.dataId = response.dataId;
self.time = response.time;
self.generatedName = "????????? TODO: ???????" //response.generatedName; self.generatedName = "????????? TODO: ???????" //response.generatedName;
if(self.dataId !== -1) { if (!isNullOrUndefined(self.dataId)) {
self.trackSource = self.httpService.createRESTCall2({ self.trackSource = this.dataService.getUrl(self.dataId);
api: `data/${ self.dataId}/${self.generatedName}`,
addURLToken: true,
});
} else { } else {
self.trackSource = ''; self.trackSource = '';
} }
self.covers = self.dataService.getCoverListUrl(response.covers); self.covers = self.dataService.getListUrl(response.covers);
self.generateName(); self.generateName();
if (!isNullOrUndefined(self.artists) && self.artists.length !== 0) { if (!isNullOrUndefined(self.artists) && self.artists.length !== 0) {
@@ -240,29 +231,28 @@ export class TrackScene implements OnInit {
}).catch((response5) => { }).catch((response5) => {
// nothing to do ... // nothing to do ...
}); });
self.albumService.getTrack(self.albumId) self.trackService.getTracksWithAlbumId(self.albumId)
.then((response6:any) => { .then((response6: Track[]) => {
// console.log("saison property: " + JSON.stringify(response, null, 2));
self.haveNext = null; self.haveNext = null;
self.havePrevious = null; self.havePrevious = null;
for (let iii = 0; iii < response6.length; iii++) { for (let iii = 0; iii < response6.length; iii++) {
if(isNullOrUndefined(response6[iii].episode)) { if (isNullOrUndefined(response6[iii].track)) {
continue; continue;
} }
if(response6[iii].episode < self.episode) { if (response6[iii].track < self.track) {
if (self.havePrevious === null) { if (self.havePrevious === null) {
self.havePrevious = response6[iii]; self.havePrevious = response6[iii];
} else if(self.havePrevious.episode < response6[iii].episode) { } else if (self.havePrevious.episode < response6[iii].track) {
self.havePrevious = response6[iii]; self.havePrevious = response6[iii];
} }
} else if(response6[iii].episode > self.episode) { } else if (response6[iii].track > self.track) {
if (self.haveNext === null) { if (self.haveNext === null) {
self.haveNext = response6[iii]; self.haveNext = response6[iii];
} else if(self.haveNext.episode > response6[iii].episode) { } else if (self.haveNext.episode > response6[iii].track) {
self.haveNext = response6[iii]; self.haveNext = response6[iii];
} }
} }
self.covers.push(self.dataService.getCoverUrl(response6[iii])); //self.covers.push(self.dataService.getUrl(response6[iii].covers));
} }
}).catch((response7: any) => { }).catch((response7: any) => {
@@ -275,11 +265,10 @@ export class TrackScene implements OnInit {
self.error = 'Can not get the data'; self.error = 'Can not get the data';
self.name = ''; self.name = '';
self.description = ''; self.description = '';
self.episode = undefined; self.track = undefined;
self.artists = undefined; self.artists = undefined;
self.albumId = undefined; self.albumId = undefined;
self.dataId = -1; self.dataId = "";
self.time = undefined;
self.generatedName = ''; self.generatedName = '';
self.trackSource = ''; self.trackSource = '';
self.covers = undefined; self.covers = undefined;
@@ -557,10 +546,12 @@ export class TrackScene implements OnInit {
// convert it and send it to the server // convert it and send it to the server
let self = this; let self = this;
console.log("not implemented right now...");
/*
this.videoCanva.toBlob((blob) => { this.videoCanva.toBlob((blob) => {
self.trackService.uploadCoverBlob(blob, this.idTrack); self.trackService.uploadCoverBlob(blob, this.idTrack);
}, 'image/jpeg', 0.95); }, 'image/jpeg', 0.95);
*/
/* /*
let tmpUrl = this.videoCanva.toDataURL('image/jpeg', 0.95); let tmpUrl = this.videoCanva.toDataURL('image/jpeg', 0.95);
fetch(tmpUrl) fetch(tmpUrl)
@@ -571,3 +562,4 @@ export class TrackScene implements OnInit {
*/ */
} }
} }

View File

@@ -32,12 +32,14 @@
</tbody> </tbody>
</table> </table>
</div> </div>
@if(parsedElement.length !== 0) {
<div *ngIf="this.parsedElement.length !== 0" class="title"> <div class="title">
Meta-data: Meta-data:
</div> </div>
}
<div class="clear"><br/></div> <div class="clear"><br/></div>
<div *ngIf="this.parsedElement.length !== 0" class="fill-all"> @if(parsedElement.length !== 0) {
<div class="fill-all">
<div class="request_raw_table"> <div class="request_raw_table">
<table> <table>
<colgroup> <colgroup>
@@ -59,9 +61,11 @@
<tr> <tr>
<td class="left-colomn"></td> <td class="left-colomn"></td>
<td class="right-colomn"> <td class="right-colomn">
<select [ngModel]="genreId" <!--<select [ngModel]="genreId"-->
(ngModelChange)="onChangeGender($event)"> <select (ngModelChange)="onChangeGender($event)">
<option *ngFor="let element of listGender" [ngValue]="element.value">{{element.label}}</option> @for (element of listGender; track element.value;) {
<option [ngValue]="element.value">{{element.label}}</option>
}
</select> </select>
</td> </td>
<td class="tool-colomn"> <td class="tool-colomn">
@@ -87,7 +91,9 @@
<td class="right-colomn"> <td class="right-colomn">
<select [ngModel]="artistId" <select [ngModel]="artistId"
(ngModelChange)="onChangeArtist($event)"> (ngModelChange)="onChangeArtist($event)">
<option *ngFor="let element of listArtist" [ngValue]="element.value">{{element.label}}</option> @for (element of listArtist; track element.value;) {
<option [ngValue]="element.value">{{element.label}}</option>
}
</select> </select>
</td> </td>
<td class="tool-colomn"> <td class="tool-colomn">
@@ -111,9 +117,11 @@
<tr> <tr>
<td class="left-colomn"></td> <td class="left-colomn"></td>
<td class="right-colomn"> <td class="right-colomn">
<select [ngModel]="albumId" <select [ngModel]="albumId">
(ngModelChange)="onChangeAlbum($event)"> <!--(ngModelChange)="onChangeAlbum($event)">-->
<option *ngFor="let element of listAlbum" [ngValue]="element.value">{{element.label}}</option> @for (element of listAlbum; track element.value;) {
<option [ngValue]="element.value">{{element.label}}</option>
}
</select> </select>
</td> </td>
<td class="tool-colomn"> <td class="tool-colomn">
@@ -142,7 +150,8 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let data of this.parsedElement"> @for (data of parsedElement; track data.trackId;) {
<tr>
<td class="left-colomn"> <td class="left-colomn">
<input type="number" <input type="number"
pattern="[0-9]{0-4}" pattern="[0-9]{0-4}"
@@ -159,19 +168,22 @@
(input)="onTitle(data, $event.target.value)" (input)="onTitle(data, $event.target.value)"
[class.error]="data.title === ''" [class.error]="data.title === ''"
/> />
<span *ngIf="data.nameDetected === true" class="error"> @if(data.nameDetected === true) {
<span class="error">
^^^This title already exist !!! ^^^This title already exist !!!
</span> </span>
}
</td> </td>
<td class="tool-colomn" > <td class="tool-colomn" >
<button class="button color-button-cancel color-shadow-black" <button class="button color-button-cancel color-shadow-black"
(click)="removeElmentFromList(data, $event.target.value)" (click)="removeElementFromList(data, $event.target.value)"
type="submit" type="submit"
alt="Delete"> alt="Delete">
<i class="material-icons">delete</i> <i class="material-icons">delete</i>
</button> </button>
</td> </td>
</tr> </tr>
}
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -185,7 +197,8 @@
</button> </button>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
<div class="request_raw_table" *ngIf="this.listFileInBdd"> @if(listFileInBdd) {
<div class="request_raw_table">
<table> <table>
<colgroup> <colgroup>
<col style="width:10%"> <col style="width:10%">
@@ -199,15 +212,20 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let data of this.listFileInBdd"> @for (data of listFileInBdd; track data.id;) {
<tr>
<td class="left-colomn" [class.error]="data.episodeDetected === true">{{data.episode}}</td> <td class="left-colomn" [class.error]="data.episodeDetected === true">{{data.episode}}</td>
<td class="right-colomn" [class.error]="data.nameDetected === true">{{data.name}}</td> <td class="right-colomn" [class.error]="data.nameDetected === true">{{data.name}}</td>
</tr> </tr>
}
</tbody> </tbody>
</table> </table>
</div> </div>
}
</div> </div>
<div *ngIf="this.parsedElement.length !== 0" class="fill-all"> }
@if(parsedElement.length !== 0) {
<div class="fill-all">
<div class="request_raw_table"> <div class="request_raw_table">
<table> <table>
<colgroup> <colgroup>
@@ -215,24 +233,19 @@
<col style="width:80%"> <col style="width:80%">
</colgroup> </colgroup>
<tbody> <tbody>
<!-- no need @for (data of parsedFailedElement; track data.id;) {
<tr *ngFor="let data of this.parsedElement"> <tr>
<td class="left-colomn">Keep:</td>
<td class="right-colomn">
{{data.file.name}}
</td>
</tr>
-->
<tr *ngFor="let data of this.parsedFailedElement">
<td class="left-colomn">Rejected:</td> <td class="left-colomn">Rejected:</td>
<td class="right-colomn"> <td class="right-colomn">
{{data.file.name}}<br/> ==&gt; {{data.reason}} {{data.file.name}}<br/> ==&gt; {{data.reason}}
</td> </td>
</tr> </tr>
}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
}
</div> </div>
<upload-progress [mediaTitle]="upload.labelMediaTitle" <upload-progress [mediaTitle]="upload.labelMediaTitle"
[mediaUploaded]="upload.mediaSendSize" [mediaUploaded]="upload.mediaSendSize"

View File

@@ -5,12 +5,12 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { UploadProgress,PopInService, isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
import { } from '@kangaroo-and-rabbit/kar-cw/popin/upload-progress/upload-progress';
import { Artist, Gender } from 'app/back-api';
import { GenderService, ArtistService, TrackService, AlbumService } from 'app/service';
import { GenderService, ArtistService, TrackService, ArianeService, AlbumService } from 'app/service';
import { NodeData } from 'common/model';
import { UploadProgress } from 'common/popin/upload-progress/upload-progress';
import { PopInService } from 'common/service';
import { isNullOrUndefined } from 'common/utils';
export class ElementList { export class ElementList {
constructor( constructor(
@@ -22,21 +22,22 @@ export class ElementList {
export class FileParsedElement { export class FileParsedElement {
public isSended: boolean = false; public isSended: boolean = false;
public nameDetected: boolean = false; public nameDetected: boolean = false;
public episodeDetected: boolean = false;s public trackIdDetected: boolean = false; s
constructor( constructor(
public file: File, public file: File,
public artist: string, public artist: string,
public album: string, public album: string,
public trackId: number, public trackId: number,
public title: string) { public title: string) {
// nothiing to do. // nothing to do.
} }
} }
export class FileFailParsedElement { export class FileFailParsedElement {
constructor( constructor(
public id: number,
public file: File, public file: File,
public reason: string) { public reason: string) {
// nothiing to do. // nothing to do.
} }
} }
@@ -56,7 +57,7 @@ export class UploadScene implements OnInit {
albumId: number = null; albumId: number = null;
needSend: boolean = false; needSend: boolean = false;
// list of all files already registered in the bdd to compare with the curent list of files. // list of all files already registered in the bdd to compare with the current list of files.
listFileInBdd: any[] = undefined; listFileInBdd: any[] = undefined;
// section tha define the upload value to display in the pop-in of upload // section tha define the upload value to display in the pop-in of upload
@@ -81,7 +82,7 @@ export class UploadScene implements OnInit {
*/ */
config = { config = {
displayKey: 'description', // if objects array passed which key to be displayed defaults to description displayKey: 'description', // if objects array passed which key to be displayed defaults to description
search: true, // true/false for the search functionlity defaults to false, search: true, // true/false for the search functionality defaults to false,
height: 'auto', // height of the list so that if there are more no of items it can show a scroll defaults to auto. With auto height scroll will never appear height: 'auto', // height of the list so that if there are more no of items it can show a scroll defaults to auto. With auto height scroll will never appear
placeholder: 'Select', // text to be displayed when no item is selected defaults to Select, placeholder: 'Select', // text to be displayed when no item is selected defaults to Select,
customComparator: () => { }, // a custom function using which user wants to sort the items. default is undefined and Array.sort() will be used in that case, customComparator: () => { }, // a custom function using which user wants to sort the items. default is undefined and Array.sort() will be used in that case,
@@ -99,7 +100,6 @@ export class UploadScene implements OnInit {
private artistService: ArtistService, private artistService: ArtistService,
private albumService: AlbumService, private albumService: AlbumService,
private trackService: TrackService, private trackService: TrackService,
private arianeService: ArianeService,
private popInService: PopInService) { private popInService: PopInService) {
// nothing to do. // nothing to do.
} }
@@ -115,11 +115,6 @@ export class UploadScene implements OnInit {
this.needSend = false; this.needSend = false;
} }
} }
/*
if(isNullOrUndefined(this.genderId)) {
this.needSend = false;
}
*/
return this.needSend; return this.needSend;
} }
@@ -137,7 +132,7 @@ export class UploadScene implements OnInit {
console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`); console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`);
}); });
this.genderService.getOrder() this.genderService.getOrder()
.then((response2: NodeData[]) => { .then((response2: Gender[]) => {
//console.error(`Keep gender : ${ JSON.stringify(response2, null, 2)} ==> ${response2.length}`); //console.error(`Keep gender : ${ JSON.stringify(response2, null, 2)} ==> ${response2.length}`);
for (let iii = 0; iii < response2.length; iii++) { for (let iii = 0; iii < response2.length; iii++) {
self.listGender.push({ value: response2[iii].id, label: response2[iii].name }); self.listGender.push({ value: response2[iii].id, label: response2[iii].name });
@@ -191,7 +186,9 @@ export class UploadScene implements OnInit {
return; return;
} }
let self = this; let self = this;
this.artistService.getAlbum(this.artistId) this.trackService.getAlbumIdsOfAnArtist(this.artistId)
.then((listAlbumIds: number[]) => {
this.albumService.getAll(listAlbumIds)
.then((response2) => { .then((response2) => {
for (let iii = 0; iii < response2.length; iii++) { for (let iii = 0; iii < response2.length; iii++) {
self.listAlbum.push({ value: response2[iii].id, label: response2[iii].name }); self.listAlbum.push({ value: response2[iii].id, label: response2[iii].name });
@@ -199,6 +196,7 @@ export class UploadScene implements OnInit {
}).catch((response2) => { }).catch((response2) => {
console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`); console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`);
}); });
});
} }
onArtist(value: any): void { onArtist(value: any): void {
this.globalArtist = value; this.globalArtist = value;
@@ -250,18 +248,19 @@ export class UploadScene implements OnInit {
data.title = value; data.title = value;
this.updateNeedSend(); this.updateNeedSend();
} }
removeElmentFromList(data: FileParsedElement, value: any): void {
removeElementFromList(data: FileParsedElement, value: any): void {
for (let iii = 0; iii < this.parsedElement.length; iii++) { for (let iii = 0; iii < this.parsedElement.length; iii++) {
if (this.parsedElement[iii] === data) { if (this.parsedElement[iii] === data) {
this.parsedElement.splice(iii, 1); this.parsedElement.splice(iii, 1);
break; break;
} }
} }
this.parsedFailedElement.push(new FileFailParsedElement(data.file, 'Removed by user.')); this.parsedFailedElement.push(new FileFailParsedElement(this.parsedFailedElement.length, data.file, 'Removed by user.'));
this.updateNeedSend(); this.updateNeedSend();
} }
onEpisode(data: FileParsedElement, value: any): void { onTrackId(data: FileParsedElement, value: any): void {
data.trackId = value; data.trackId = value;
// console.log("change episode ID: " + value + " ==> " + this.parseEpisode.toString()); // console.log("change episode ID: " + value + " ==> " + this.parseEpisode.toString());
this.updateNeedSend(); this.updateNeedSend();
@@ -319,7 +318,7 @@ export class UploadScene implements OnInit {
if (isNaN(trackIdNumber)) { if (isNaN(trackIdNumber)) {
trackIdNumber = undefined; trackIdNumber = undefined;
} }
// remove extention // remove extension
title = title.replace(new RegExp('\\.(webm|WEBM|Webm)'), ''); title = title.replace(new RegExp('\\.(webm|WEBM|Webm)'), '');
let tmp = new FileParsedElement(file, artist, album, trackIdNumber, title); let tmp = new FileParsedElement(file, artist, album, trackIdNumber, title);
console.log(`==>${JSON.stringify(tmp)}`); console.log(`==>${JSON.stringify(tmp)}`);
@@ -341,12 +340,12 @@ export class UploadScene implements OnInit {
this.updateNeedSend(); this.updateNeedSend();
return; return;
} }
// we verify fith the first value to remove all unknown ... // we verify with the first value to remove all unknown ...
// clean different gender: // clean different gender:
/*for(let iii = 1; iii < this.parsedElement.length; iii++) { /*for(let iii = 1; iii < this.parsedElement.length; iii++) {
console.log(`check gender [${ iii + 1 }/${ this.parsedElement.length }] '${ this.parsedElement[0].gender } !== ${ this.parsedElement[iii].gender }'`); console.log(`check gender [${ iii + 1 }/${ this.parsedElement.length }] '${ this.parsedElement[0].gender } !== ${ this.parsedElement[iii].gender }'`);
if(this.parsedElement[0].gender !== this.parsedElement[iii].gender) { if(this.parsedElement[0].gender !== this.parsedElement[iii].gender) {
this.parsedFailedElement.push(new FileFailParsedElement(this.parsedElement[iii].file, 'Remove from list due to wrong gender value')); this.parsedFailedElement.push(new FileFailParsedElement(this.parsedFailedElement.length, this.parsedElement[iii].file, 'Remove from list due to wrong gender value'));
console.log(`Remove from list (!= playlist) : [${ iii + 1 }/${ this.parsedElement.length }] '${ this.parsedElement[iii].file.name }'`); console.log(`Remove from list (!= playlist) : [${ iii + 1 }/${ this.parsedElement.length }] '${ this.parsedElement[iii].file.name }'`);
this.parsedElement.splice(iii, 1); this.parsedElement.splice(iii, 1);
iii--; iii--;
@@ -357,7 +356,7 @@ export class UploadScene implements OnInit {
for (let iii = 1; iii < this.parsedElement.length; iii++) { for (let iii = 1; iii < this.parsedElement.length; iii++) {
console.log(`check artist [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[0].artist} !== ${this.parsedElement[iii].artist}'`); console.log(`check artist [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[0].artist} !== ${this.parsedElement[iii].artist}'`);
if (this.parsedElement[0].artist !== this.parsedElement[iii].artist) { if (this.parsedElement[0].artist !== this.parsedElement[iii].artist) {
this.parsedFailedElement.push(new FileFailParsedElement(this.parsedElement[iii].file, 'Remove from list due to wrong artist value')); this.parsedFailedElement.push(new FileFailParsedElement(this.parsedFailedElement.length, this.parsedElement[iii].file, 'Remove from list due to wrong artist value'));
console.log(`Remove from list (!= artist) : [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[iii].file.name}'`); console.log(`Remove from list (!= artist) : [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[iii].file.name}'`);
this.parsedElement.splice(iii, 1); this.parsedElement.splice(iii, 1);
iii--; iii--;
@@ -367,7 +366,7 @@ export class UploadScene implements OnInit {
for (let iii = 1; iii < this.parsedElement.length; iii++) { for (let iii = 1; iii < this.parsedElement.length; iii++) {
console.log(`check album [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[0].album} !== ${this.parsedElement[iii].album}'`); console.log(`check album [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[0].album} !== ${this.parsedElement[iii].album}'`);
if (this.parsedElement[0].album !== this.parsedElement[iii].album) { if (this.parsedElement[0].album !== this.parsedElement[iii].album) {
this.parsedFailedElement.push(new FileFailParsedElement(this.parsedElement[iii].file, 'Remove from list due to wrong album value')); this.parsedFailedElement.push(new FileFailParsedElement(this.parsedFailedElement.length, this.parsedElement[iii].file, 'Remove from list due to wrong album value'));
console.log(`Remove from list (!= album) : [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[iii].file.name}'`); console.log(`Remove from list (!= album) : [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[iii].file.name}'`);
this.parsedElement.splice(iii, 1); this.parsedElement.splice(iii, 1);
iii--; iii--;
@@ -404,7 +403,7 @@ export class UploadScene implements OnInit {
self.upload.error = `Error in the upload of the data...${value}`; self.upload.error = `Error in the upload of the data...${value}`;
}); });
} }
uploadFile(elemnent: FileParsedElement, id: number, total: number, sendDone: any, errorOccured: any): void { uploadFile(element: FileParsedElement, id: number, total: number, sendDone: any, errorOccurred: any): void {
let self = this; let self = this;
self.upload.labelMediaTitle = ''; self.upload.labelMediaTitle = '';
@@ -429,24 +428,24 @@ export class UploadScene implements OnInit {
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}s${self.globalAlbum.toString()}`; self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}s${self.globalAlbum.toString()}`;
} }
// add episode ID // add episode ID
if(!isNullOrUndefined(elemnent.trackId) && elemnent.trackId.toString().length !== 0) { if (!isNullOrUndefined(element.trackId) && element.trackId.toString().length !== 0) {
if (self.upload.labelMediaTitle.length !== 0) { if (self.upload.labelMediaTitle.length !== 0) {
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`; self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`;
} }
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle }e${ elemnent.trackId.toString()}`; self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}e${element.trackId.toString()}`;
} }
// add title // add title
if (self.upload.labelMediaTitle.length !== 0) { if (self.upload.labelMediaTitle.length !== 0) {
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`; self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`;
} }
self.upload.labelMediaTitle = `[${ id + 1 }/${ total }]${ self.upload.labelMediaTitle }${elemnent.title}`; self.upload.labelMediaTitle = `[${id + 1}/${total}]${self.upload.labelMediaTitle}${element.title}`;
self.trackService.uploadFile(elemnent.file, self.trackService.uploadFile(element.file,
self.globalGender, self.globalGender,
self.globalArtist, self.globalArtist,
self.globalAlbum, self.globalAlbum,
elemnent.trackId, element.trackId,
elemnent.title, element.title,
(count, totalTmp) => { (count, totalTmp) => {
// console.log("upload : " + count*100/totalTmp); // console.log("upload : " + count*100/totalTmp);
self.upload.mediaSendSize = count; self.upload.mediaSendSize = count;
@@ -458,7 +457,7 @@ export class UploadScene implements OnInit {
}).catch((response) => { }).catch((response) => {
// self.error = "Can not get the data"; // self.error = "Can not get the data";
console.log('Can not add the data in the system...'); console.log('Can not add the data in the system...');
errorOccured(JSON.stringify(response, null, 2)); errorOccurred(JSON.stringify(response, null, 2));
}); });
} }
@@ -479,21 +478,21 @@ export class UploadScene implements OnInit {
return false; return false;
} }
checkConcordence():void { checkConcordance(): void {
if (isNullOrUndefined(this.parsedElement)) { if (isNullOrUndefined(this.parsedElement)) {
return; return;
} }
// ckear checker // ckear checker
for (let iii = 0; iii < this.parsedElement.length; iii++) { for (let iii = 0; iii < this.parsedElement.length; iii++) {
this.parsedElement[iii].nameDetected = false; this.parsedElement[iii].nameDetected = false;
this.parsedElement[iii].episodeDetected = false; this.parsedElement[iii].trackIdDetected = false;
} }
if (isNullOrUndefined(this.listFileInBdd)) { if (isNullOrUndefined(this.listFileInBdd)) {
return; return;
} }
for (let iii = 0; iii < this.listFileInBdd.length; iii++) { for (let iii = 0; iii < this.listFileInBdd.length; iii++) {
this.listFileInBdd[iii].nameDetected = false; this.listFileInBdd[iii].nameDetected = false;
this.listFileInBdd[iii].episodeDetected = false; this.listFileInBdd[iii].trackIdDetected = false;
} }
for (let iii = 0; iii < this.parsedElement.length; iii++) { for (let iii = 0; iii < this.parsedElement.length; iii++) {
for (let jjj = 0; jjj < this.listFileInBdd.length; jjj++) { for (let jjj = 0; jjj < this.listFileInBdd.length; jjj++) {
@@ -502,8 +501,8 @@ export class UploadScene implements OnInit {
this.listFileInBdd[jjj].nameDetected = true; this.listFileInBdd[jjj].nameDetected = true;
} }
if (this.parsedElement[iii].trackId === this.listFileInBdd[jjj].episode) { if (this.parsedElement[iii].trackId === this.listFileInBdd[jjj].episode) {
this.parsedElement[iii].episodeDetected = true; this.parsedElement[iii].trackIdDetected = true;
this.listFileInBdd[jjj].episodeDetected = true; this.listFileInBdd[jjj].trackIdDetected = true;
} }
} }
} }
@@ -519,14 +518,14 @@ export class UploadScene implements OnInit {
// no album check only the artist files. // no album check only the artist files.
if (isNullOrUndefined(this.globalAlbum)) { if (isNullOrUndefined(this.globalAlbum)) {
console.error(`NO ALBUM ==> check artist ID...`); console.error(`NO ALBUM ==> check artist ID...`);
self.artistService.getAllTracks(self.artistId) self.trackService.getTracksOfAnArtist(self.artistId)
.then((response: any[]) => { .then((response: any[]) => {
self.listFileInBdd = response; self.listFileInBdd = response;
console.error(`find track: ${JSON.stringify(response, null, 2)}`); console.error(`find track: ${JSON.stringify(response, null, 2)}`);
// for (let iii = 0; iii<response.length; iii++) { // for (let iii = 0; iii<response.length; iii++) {
// console.log(" - " + JSON.stringify(response[iii])); // console.log(" - " + JSON.stringify(response[iii]));
// } // }
self.checkConcordence(); self.checkConcordance();
}).catch((response) => { }).catch((response) => {
self.listFileInBdd = undefined; self.listFileInBdd = undefined;
}); });
@@ -536,9 +535,10 @@ export class UploadScene implements OnInit {
self.albumId = undefined; self.albumId = undefined;
console.error(`ALBUM ==> check album values...`); console.error(`ALBUM ==> check album values...`);
// set 1 find the ID of the album: // set 1 find the ID of the album:
this.artistService.getAlbum(this.artistId) this.trackService.getAlbumIdsOfAnArtist(this.artistId)
.then((response: any[]) => { .then((listAlbumIds: number[]) => {
console.log(`find album: ${JSON.stringify(response, null, 2)}`); this.artistService.getAll(listAlbumIds)
.then((response: Artist[]) => {
for (let iii = 0; iii < response.length; iii++) { for (let iii = 0; iii < response.length; iii++) {
// console.log(" - " + JSON.stringify(response[iii]) + 'compare with : ' + JSON.stringify(self.globalAlbum)); // console.log(" - " + JSON.stringify(response[iii]) + 'compare with : ' + JSON.stringify(self.globalAlbum));
if (response[iii].name === `${self.globalAlbum}`) { if (response[iii].name === `${self.globalAlbum}`) {
@@ -549,7 +549,7 @@ export class UploadScene implements OnInit {
if (isNullOrUndefined(self.albumId)) { if (isNullOrUndefined(self.albumId)) {
return; return;
} }
self.albumService.getTrack(self.albumId) self.trackService.getTracksWithAlbumId(self.albumId)
.then((response2: any[]) => { .then((response2: any[]) => {
self.listFileInBdd = response2; self.listFileInBdd = response2;
console.log(`find album: ${JSON.stringify(response, null, 2)}`); console.log(`find album: ${JSON.stringify(response, null, 2)}`);
@@ -557,10 +557,11 @@ export class UploadScene implements OnInit {
// for (let iii = 0; iii<response2.length; iii++) { // for (let iii = 0; iii<response2.length; iii++) {
// console.log(" - " + JSON.stringify(response2[iii])); // console.log(" - " + JSON.stringify(response2[iii]));
// } // }
self.checkConcordence(); self.checkConcordance();
}).catch((response3) => { }).catch((response3) => {
self.listFileInBdd = undefined; self.listFileInBdd = undefined;
}); });
})
}).catch((response4) => { }).catch((response4) => {
self.listFileInBdd = undefined; self.listFileInBdd = undefined;
}); });

View File

@@ -0,0 +1,95 @@
import { DataStore, DataTools, TypeCheck, isNullOrUndefined } from "@kangaroo-and-rabbit/kar-cw";
export class GenericDataService<TYPE> {
protected dataStore: DataStore<TYPE>;
setStore(dataStore: DataStore<TYPE>) {
this.dataStore = dataStore;
}
gets(): Promise<TYPE[]> {
return this.dataStore.getData();
}
get(id: number): Promise<TYPE> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: TYPE[]) => {
let data = DataTools.get(response, id);
if (isNullOrUndefined(data)) {
reject('Data does not exist in the local BDD');
return;
}
resolve(data);
return;
}).catch((response) => {
reject(response);
});
});
}
getAll(ids: number[]): Promise<TYPE[]> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: TYPE[]) => {
let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.EQUAL,
key: 'id',
value: ids,
},
]);
resolve(data);
return;
}).catch((response) => {
reject(response);
});
});
}
getLike(value: string): Promise<TYPE[]> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: TYPE[]) => {
let data = DataTools.getNameLike(response, value);
if (isNullOrUndefined(data) || data.length === 0) {
reject('Data does not exist in the local BDD');
return;
}
resolve(data);
return;
}).catch((response) => {
reject(response);
});
});
}
getOrder(): Promise<TYPE[]> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: TYPE[]) => {
let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.NOT_EQUAL,
key: 'id',
value: [undefined, null],
},
],
["name", "id"],
);
resolve(data);
}).catch((response) => {
console.log(`[E] ${self.constructor.name}: can not retrieve BDD values`);
reject(response);
});
});
}
}

View File

@@ -1,182 +0,0 @@
import { isNodeData, NodeData } from "common/model";
import { HttpWrapperService, BddService } from "common/service";
import { DataInterface, isArrayOf, isNullOrUndefined, TypeCheck } from "common/utils";
export class GenericInterfaceModelDB {
constructor(
protected serviceName: string,
protected http: HttpWrapperService,
protected bdd: BddService) {
// nothing to do ...
}
gets(): Promise<NodeData[]> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get(self.serviceName)
.then((response: DataInterface) => {
let data = response.gets();
if (isNullOrUndefined(data)) {
reject('Data does not exist in the local BDD');
return;
}
resolve(data);
return;
}).catch((response) => {
reject(response);
});
});
}
getLike(nameArtist: string): any {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get(self.serviceName)
.then((response: DataInterface) => {
let data = response.getNameLike(nameArtist);
if (data === null || data === undefined || data.length === 0) {
reject('Data does not exist in the local BDD');
return;
}
resolve(data);
return;
}).catch((response) => {
reject(response);
});
});
}
getOrder(): Promise<NodeData[]> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get(self.serviceName)
.then((response: DataInterface) => {
let data = response.getsWhere([
{
check: TypeCheck.NOT_EQUAL,
key: 'id',
value: [undefined, null],
},
],
['name', 'id']);
//data = response.gets();
if (isArrayOf(data, isNodeData)) {
resolve(data);
}
reject("The model is wrong ...");
}).catch((response) => {
console.log(`[E] ${self.constructor.name}: can not retrive BDD values`);
reject(response);
});
});
}
get(id: number): Promise<NodeData> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get(self.serviceName)
.then((response: DataInterface) => {
let data = response.get(id);
if (isNullOrUndefined(data)) {
reject('Data does not exist in the local BDD');
return;
}
resolve(data);
return;
}).catch((response) => {
reject(response);
});
});
}
getAll(ids: number[]): Promise<NodeData[]> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get(self.serviceName)
.then((response: DataInterface) => {
let data = response.getsWhere([
{
check: TypeCheck.EQUAL,
key: 'id',
value: ids,
},
],
['name', 'id']);
resolve(data);
return;
}).catch((response) => {
reject(response);
});
});
}
getData(): Promise<NodeData[]> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get(self.serviceName)
.then((response: DataInterface) => {
let data = response.gets();
resolve(data);
}).catch((response) => {
console.log(`[E] ${self.constructor.name}: can not retrive BDD values`);
reject(response);
});
});
}
insert(data: any): any {
let ret = this.http.postSpecific([this.serviceName], data);
return this.bdd.addAfterPost(this.serviceName, ret);
}
patch(id: number, data: any): any {
let ret = this.http.patchSpecific([this.serviceName, id], data);
return this.bdd.setAfterPut(this.serviceName, id, ret);
}
delete(id: number): any {
let ret = this.http.deleteSpecific([this.serviceName, id]);
return this.bdd.delete(this.serviceName, id, ret);
}
deleteCover(nodeId: number, coverId: number) {
let self = this;
return new Promise((resolve, reject) => {
self.http.getSpecific([this.serviceName, nodeId, 'rm_cover', coverId])
.then((response) => {
let data = response;
if (data === null || data === undefined) {
reject('error retrive data from server');
return;
}
self.bdd.asyncSetInDB(self.serviceName, nodeId, data);
resolve(data);
}).catch((response) => {
reject(response);
});
});
}
uploadCover(file: File,
nodeId: number,
progress: any = null) {
const formData = new FormData();
formData.append('fileName', file.name);
formData.append('id', nodeId.toString());
formData.append('file', file);
let self = this;
return new Promise((resolve, reject) => {
self.http.uploadMultipart(`${this.serviceName}/${nodeId}/add_cover/`, formData, progress)
.then((response) => {
let data = response;
if (data === null || data === undefined) {
reject('error retrive data from server');
return;
}
self.bdd.asyncSetInDB(self.serviceName, nodeId, data);
resolve(data);
}).catch((response) => {
reject(response);
});
});
}
}

View File

@@ -5,76 +5,134 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { NodeData } from 'common/model';
import { HttpWrapperService, BddService } from 'common/service'; import { Album, AlbumResource, UUID } from 'app/back-api';
import { DataInterface, TypeCheck } from 'common/utils'; import { RESTConfig, isArrayOf } from 'app/back-api/rest-tools';
import { GenericInterfaceModelDB } from './GenericInterfaceModelDB'; import { environment } from 'environments/environment';
import { GenericDataService } from './GenericDataService';
import { DataTools, DataStore, SessionService, TypeCheck, isNumber } from '@kangaroo-and-rabbit/kar-cw';
@Injectable() @Injectable()
export class AlbumService extends GenericInterfaceModelDB { export class AlbumService extends GenericDataService<Album> {
constructor(http: HttpWrapperService, getRestConfig(): RESTConfig {
bdd: BddService) { return {
super('album', http, bdd); server: environment.server.karusic,
token: this.session.getToken()
} }
getAllTracksForAlbums(idAlbums: number[]): Promise<number[]> { }
private lambdaGets(): Promise<Album[]> {
const self = this;
return AlbumResource.gets({ restConfig: this.getRestConfig() });
}
constructor(private session: SessionService) {
super();
console.log('Start AlbumService');
this.setStore(new DataStore<Album>(() => this.lambdaGets()));
}
insert(data: Album): Promise<Album> {
const self = this;
return new Promise((resolve, reject) => {
AlbumResource.post({
restConfig: this.getRestConfig(),
data
}).then((value: Album) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
});
});
}
patch(id: number, data: Album): Promise<Album> {
const self = this;
return new Promise((resolve, reject) => {
AlbumResource.patch({
restConfig: this.getRestConfig(),
params: {
id
},
data
}).then((value: Album) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
});
});
}
delete(id: number): Promise<void> {
const self = this;
return new Promise((resolve, reject) => {
AlbumResource.remove({
restConfig: this.getRestConfig(),
params: {
id
}
}).then(() => {
self.dataStore.delete(id);
resolve();
}).catch((error) => {
reject(error);
});
});
}
deleteCover(id: number, coverId: UUID): Promise<Album> {
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('track') AlbumResource.removeCover({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ params: {
{ id,
check: TypeCheck.EQUAL, coverId
key: 'albumId',
value: idAlbums,
},
],
[ 'name' ]); // tODO : set the Id in the track ...
// filter with artist- ID !!!
const listId = DataInterface.extractLimitOne(data, "id");
resolve(listId);
}).catch((response) => {
reject(response);
});
});
} }
/** }).then((value) => {
* Get all the track for a specific album self.dataStore.updateValue(value);
* @param idAlbum - Id of the album. resolve(value);
* @returns a promise on the list of track elements }).catch((error) => {
*/ reject(error);
getTrack(idAlbum:number): Promise<NodeData[]> { });
});
}
uploadCover(id: number,
file: File,
progress: any = null): Promise<Album> {
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('track') AlbumResource.uploadCover({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ params: {
{ id,
check: TypeCheck.EQUAL,
key: 'albumId',
value: idAlbum,
}, },
], data: {
[ 'name' ]); // tODO : set the Id in the track ... file,
resolve(data); fileName: file.name
}).catch((response) => { }
reject(response); }).then((value) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
}); });
}); });
} }
/** /**
* Get all the artists for a specific album * Get all the artists for a specific album
* @param idAlbum - Id of the album. * @param idAlbum - Id of the album.
* @returns a promise on the list of Artist names for this album * @returns a promise on the list of Artist ID for this album
*/ */
getArtists(idAlbum:number): Promise<String[]> { getArtists(idAlbum: number): Promise<number[]> {
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('track') self.gets()
.then((response: DataInterface) => { .then((response: Album[]) => {
let data = response.getsWhere([ let data = DataTools.getsWhere(response,
[
{ {
check: TypeCheck.EQUAL, check: TypeCheck.EQUAL,
key: 'albumId', key: 'albumId',
@@ -83,51 +141,17 @@ export class AlbumService extends GenericInterfaceModelDB {
], ],
['name']); ['name']);
// filter with artist- ID !!! // filter with artist- ID !!!
const listArtistId = DataInterface.extractLimitOneList(data, "artists"); const listArtistId = DataTools.extractLimitOneList(data, "artists");
//console.log(`${idAlbum} ==> List Of ids: ${JSON.stringify(listArtistId, null, 2)} `); if (isArrayOf(listArtistId, isNumber)) {
self.bdd.get('artist') resolve(listArtistId);
.then((response:DataInterface) => { } else {
let dataArtist = response.getsWhere([ reject(`Fail to get the ids (impossible case) ${listArtistId}`);
{ }
check: TypeCheck.EQUAL,
key: 'id',
value: listArtistId,
},
], [ 'name']);
const listArtistNames = DataInterface.extractLimitOne(dataArtist, "name");
resolve(listArtistNames);
return;
}).catch((response) => {
reject(response);
});
}).catch((response) => { }).catch((response) => {
reject(response); reject(response);
}); });
}); });
} }
/**
* Get the number of track in this saison ID
* @param AlbumId - Id of the album.
* @returns The number of element present in this saison
*/
countTrack(AlbumId:number): Promise<number> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get('track')
.then((response: DataInterface) => {
let data = response.getsWhere([
{
check: TypeCheck.EQUAL,
key: 'albumId',
value: AlbumId,
},
]);
resolve(data.length);
}).catch((response) => {
reject(response);
});
});
}
} }

View File

@@ -14,8 +14,8 @@ import { ArtistService } from './artist';
import { AlbumService } from './album'; import { AlbumService } from './album';
import { TrackService } from './track'; import { TrackService } from './track';
import { environment } from 'environments/environment'; import { environment } from 'environments/environment';
import { NodeData } from 'common/model'; import { NodeSmall } from 'app/back-api';
import { isNullOrUndefined, isStringNullOrUndefined, isUndefined } from 'common/utils'; import { isNullOrUndefined, isStringNullOrUndefined, isUndefined } from '@kangaroo-and-rabbit/kar-cw';
export class InputOrders { export class InputOrders {
public genderId: number = undefined; public genderId: number = undefined;
@@ -58,7 +58,7 @@ export class ArianeService {
private artistService: ArtistService, private artistService: ArtistService,
private albumService: AlbumService, private albumService: AlbumService,
private trackService: TrackService) { private trackService: TrackService) {
//console.log('Start ArianeService'); console.log('Start ArianeService');
//this.route. //this.route.
let self = this; let self = this;
this.router.events.subscribe((event: any) => { this.router.events.subscribe((event: any) => {
@@ -95,7 +95,6 @@ export class ArianeService {
return undefined; return undefined;
} }
return parseInt(valueStr, 10); return parseInt(valueStr, 10);
} }
updateProperties() { updateProperties() {
@@ -103,7 +102,6 @@ export class ArianeService {
while (!isNullOrUndefined(elem.firstChild)) { while (!isNullOrUndefined(elem.firstChild)) {
elem = elem.firstChild; elem = elem.firstChild;
} }
//console.log(`!!!!!!!!!!!!!!!!!!!!!!!!!! ${JSON.stringify(elem.snapshot.paramMap)}`);
let params = elem.snapshot.paramMap; let params = elem.snapshot.paramMap;
let segment: string[] = location.pathname.split("/"); let segment: string[] = location.pathname.split("/");
while (segment.length > 1 && (segment[0] === "" || segment[0] === environment.applName)) { while (segment.length > 1 && (segment[0] === "" || segment[0] === environment.applName)) {
@@ -197,7 +195,7 @@ export class ArianeService {
} }
let self = this; let self = this;
this.playlistService.get(id) this.playlistService.get(id)
.then((response: NodeData) => { .then((response: NodeSmall) => {
self.playlistName = response.name; self.playlistName = response.name;
self.playlistChange.emit(self.playlistId); self.playlistChange.emit(self.playlistId);
}).catch((response) => { }).catch((response) => {
@@ -223,7 +221,7 @@ export class ArianeService {
} }
let self = this; let self = this;
this.artistService.get(id) this.artistService.get(id)
.then((response: NodeData) => { .then((response: NodeSmall) => {
self.artistName = response.name; self.artistName = response.name;
self.artistChange.emit(self.artistId); self.artistChange.emit(self.artistId);
}).catch((response) => { }).catch((response) => {
@@ -249,7 +247,7 @@ export class ArianeService {
} }
let self = this; let self = this;
this.albumService.get(id) this.albumService.get(id)
.then((response: NodeData) => { .then((response: NodeSmall) => {
// self.setArtist(response.artistId); // self.setArtist(response.artistId);
self.albumName = response.name; self.albumName = response.name;
self.albumChange.emit(self.albumId); self.albumChange.emit(self.albumId);

View File

@@ -6,164 +6,119 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpWrapperService, BddService } from 'common/service'; import { Artist, ArtistResource, UUID } from 'app/back-api';
import { DataInterface, TypeCheck, isArrayOf } from 'common/utils'; import { RESTConfig } from 'app/back-api/rest-tools';
import { isNodeData, NodeData } from 'common/model'; import { environment } from 'environments/environment';
import { GenericInterfaceModelDB } from './GenericInterfaceModelDB'; import { GenericDataService } from './GenericDataService';
import { DataStore, SessionService } from '@kangaroo-and-rabbit/kar-cw';
@Injectable() @Injectable()
export class ArtistService extends GenericInterfaceModelDB { export class ArtistService extends GenericDataService<Artist> {
constructor(http: HttpWrapperService, getRestConfig(): RESTConfig {
bdd: BddService) { return {
super('artist', http, bdd); server: environment.server.karusic,
token: this.session.getToken()
}
}
private lambdaGets(): Promise<Artist[]> {
return ArtistResource.gets({ restConfig: this.getRestConfig() });
} }
constructor(private session: SessionService) {
super();
console.log('Start ArtistService');
const self = this;
this.setStore(new DataStore<Artist>(() => self.lambdaGets()));
}
insert(data: Artist): Promise<Artist> {
const self = this;
return new Promise((resolve, reject) => {
ArtistResource.post({
restConfig: this.getRestConfig(),
data
}).then((value: Artist) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
});
});
}
patch(id: number, data: Artist): Promise<Artist> {
const self = this;
return new Promise((resolve, reject) => {
ArtistResource.patch({
restConfig: this.getRestConfig(),
params: {
id
},
data
}).then((value: Artist) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
});
});
}
/** delete(id: number): Promise<void> {
* Get all the track for a specific artist const self = this;
* @param idArtist - Id of the artist. return new Promise((resolve, reject) => {
* @returns a promise on the list of track elements ArtistResource.remove({
*/ restConfig: this.getRestConfig(),
getTrackNoAlbum(idArtist:number): Promise<NodeData[]> { params: {
id
}
}).then(() => {
self.dataStore.delete(id);
resolve();
}).catch((error) => {
reject(error);
});
});
}
deleteCover(id: number, coverId: UUID): Promise<Artist> {
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('track') ArtistResource.removeCover({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ params: {
{ id,
check: TypeCheck.CONTAINS, coverId
key: 'artists', }
value: idArtist, }).then((value) => {
}, { self.dataStore.updateValue(value);
check: TypeCheck.EQUAL, resolve(value);
key: 'albumId', }).catch((error) => {
value: undefined, reject(error);
},
],
[ 'track', 'name' ]);
resolve(data);
}).catch((response) => {
reject(response);
}); });
}); });
} }
/** uploadCover(id: number,
* Get all the track for a specific artist file: File,
* @param idArtist - Id of the artist. progress: any = null): Promise<Artist> {
* @returns a promise on the list of track elements
*/
getAllTracks(idArtist:number): Promise<NodeData[]> {
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('track') ArtistResource.uploadCover({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ params: {
{ id,
check: TypeCheck.CONTAINS, },
key: 'artists', data: {
value: idArtist, file,
fileName: file.name
} }
], }).then((value) => {
[ 'track', 'name' ]); self.dataStore.updateValue(value);
resolve(data); resolve(value);
}).catch((response) => { }).catch((error) => {
reject(response); reject(error);
}); });
}); });
} }
/**
* Get the number of track in this artist ID
* @param id - Id of the artist.
* @returns The number of track present in this artist
*/
countTrack(artistId:number): Promise<number> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get('track')
.then((response:DataInterface) => {
let data = response.getsWhere([
{
check: TypeCheck.CONTAINS,
key: 'artists',
value: artistId,
},
]);
resolve(data.length);
}).catch((response) => {
reject(response);
});
});
}
/**
* Get all the album of a specific artist
* @param idArtist - ID of the artist
* @returns the required List.
*/
getAlbum(idArtist:number): Promise<NodeData[]> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get('track')
.then((response:DataInterface) => {
//console.log(" <<<========================================>>> " + idArtist);
let data = response.getsWhere([
{
check: TypeCheck.CONTAINS, //< this is for array containing
key: 'artists',
value: idArtist,
},
], [ 'id' ]);
//console.log("==> get all tracks of the artist: " + JSON.stringify(data, null, 2));
// extract a single time all value "id" in an array
const listAlbumId = DataInterface.extractLimitOne(data, "albumId");
//console.log("==> List Of ids: " + JSON.stringify(listAlbumId, null, 2));
self.bdd.get('album')
.then((response:DataInterface) => {
let dataAlbum = response.getsWhere([
{
check: TypeCheck.EQUAL,
key: 'id',
value: listAlbumId,
},
], [ 'publication', 'name', 'id' ]);
resolve(dataAlbum);
//console.log("==> get all albums: " + JSON.stringify(dataAlbum, null, 2));
return;
}).catch((response) => {
reject(response);
});
return;
}).catch((response) => {
reject(response);
});
});
}
countAlbum(idArtist:number): Promise<number> {
let self = this;
return new Promise((resolve, reject) => {
self.bdd.get('track')
.then((response:DataInterface) => {
//console.log(" <<<========================================>>> " + idArtist);
let data = response.getsWhere([
{
check: TypeCheck.CONTAINS, //< this is for array containing
key: 'artists',
value: idArtist,
},
], [ 'id' ]);
//console.log("==> get all tracks of the artist: " + JSON.stringify(data, null, 2));
// extract a single time all value "id" in an array
const listAlbumId = DataInterface.extractLimitOne(data, "albumId");
resolve(listAlbumId.length);
}).catch((response) => {
reject(response);
});
});
}
} }

View File

@@ -5,97 +5,112 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { isArrayOf, isNumberFinite } from 'common/utils'; import { SessionService, isArrayOf, isNullOrUndefined, isString } from '@kangaroo-and-rabbit/kar-cw';
import { HTTPMimeType, HTTPRequestModel, HttpWrapperService, ModelResponseHttp } from '../../common/service/http-wrapper'; import { RESTConfig, RESTUrl } from 'app/back-api/rest-tools';
import { environment } from 'environments/environment';
@Injectable() @Injectable()
export class DataService { export class DataService {
// 0: Not hide password; 1 hide password;
private serviceName:string = 'data';
constructor(private http: HttpWrapperService) { getRestConfig(): RESTConfig {
return {
server: environment.server.karusic,
token: this.session.getToken()
}
}
constructor(private session: SessionService) {
console.log('Start DataService'); console.log('Start DataService');
} }
getData():any {
return this.http.getSpecific(this.serviceName);
}
get(_id:number):any {
return this.http.getSpecific([this.serviceName, _id]);
}
uploadFile(_form:FormData, _progress:any = null) {
// return this.http.uploadFileMultipart(this.serviceName, null, _file);
return this.http.uploadMultipart(`${this.serviceName }/upload/`, _form, _progress);
}
getImage(_id:number) : Promise<ModelResponseHttp> {
return this.http.requestImage({
endPoint: this.serviceName,
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.IMAGE,
contentType: HTTPMimeType.JSON,
});
}
getImageThumbnail(_id:number) : Promise<ModelResponseHttp> {
return this.http.requestImage({
endPoint: this.serviceName + "/thumbnail/" + _id,
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.ALL,//IMAGE,
contentType: HTTPMimeType.JSON,
});
}
/** /**
* Retreive the Cover URL of a specific data id * Retrieve the Cover URL of a specific data id
* @param coverId Id of te cover * @param coverId Id of te cover
* @returns the url of the cover * @returns the url of the cover
*/ */
getCoverUrl(coverId: number): string { getUrl(dataId: string, optionalName?: string): string {
return this.http.createRESTCall2({ if (isNullOrUndefined(optionalName)) {
api: `data/${coverId}`, const url = RESTUrl({
addURLToken: true, restModel: {
endPoint: "data/{dataId}",
tokenInUrl: true,
},
restConfig: this.getRestConfig(),
params: {
dataId
}
}); });
console.log(`get URL = ${url}`);
if (environment?.replaceDataToRealServer === true) {
return url.replace("http://localhost:19080", "https://atria-soft.org");
}
return url;
}
const url = RESTUrl({
restModel: {
endPoint: "data/{dataId}/{optionalName}",
tokenInUrl: true,
},
restConfig: this.getRestConfig(),
params: {
dataId,
optionalName
}
});
if (environment?.replaceDataToRealServer === true) {
return url.replace("http://localhost:19080", "https://atria-soft.org");
}
return url;
} }
/** /**
* Retreive the list Cover URL of a specific data id * Retrieve the list Cover URL of a specific data id
* @param coverId Id of te cover * @param coverId Id of te cover
* @returns the url of the cover * @returns the url of the cover
*/ */
getCoverListUrl(coverIds?: number[]): string[] | undefined { getListUrl(dataIds?: string[]): string[] | undefined {
if(!isArrayOf(coverIds, isNumberFinite) || coverIds.length === 0) { if (!isArrayOf(dataIds, isString) || dataIds.length === 0) {
return undefined; return undefined;
} }
let covers = [] as string[]; let covers: string[] = [];
for(let iii = 0; iii < coverIds.length; iii++) { for (let iii = 0; iii < dataIds.length; iii++) {
covers.push(this.getCoverUrl(coverIds[iii])); covers.push(this.getUrl(dataIds[iii]));
} }
return covers; return covers;
} }
/** /**
* Retreive the thumbnail cover URL of a specific data id * Retrieve the thumbnail cover URL of a specific data id
* @param coverId Id of te cover * @param coverId Id of te cover
* @returns the url of the cover * @returns the url of the cover
*/ */
getCoverThumbnailUrl(coverId: number): string { getThumbnailUrl(coverId: string): string {
return this.http.createRESTCall2({ const url = RESTUrl({
api: `data/thumbnail/${coverId}`, restModel: {
addURLToken: true, endPoint: "data/thumbnail/{coverId}",
tokenInUrl: true,
},
restConfig: this.getRestConfig(),
params: {
coverId
}
}); });
if (environment?.replaceDataToRealServer === true) {
return url.replace("http://localhost:19080", "https://atria-soft.org");
}
return url;
} }
/** /**
* Retreive the list thumbnail cover URL of a specific data id * Retrieve the list thumbnail cover URL of a specific data id
* @param coverId Id of te cover * @param coverId Id of te cover
* @returns the url of the cover * @returns the url of the cover
*/ */
getCoverListThumbnailUrl(coverIds?: number[]): string[] | undefined { getListThumbnailUrl(dataIds?: string[]): string[] | undefined {
if(!isArrayOf(coverIds, isNumberFinite) || coverIds.length === 0) { if (!isArrayOf(dataIds, isString) || dataIds.length === 0) {
return undefined; return undefined;
} }
let covers = [] as string[]; let covers: string[] = [];
for(let iii = 0; iii < coverIds.length; iii++) { for (let iii = 0; iii < dataIds.length; iii++) {
covers.push(this.getCoverThumbnailUrl(coverIds[iii])); covers.push(this.getThumbnailUrl(dataIds[iii]));
} }
return covers; return covers;
} }

View File

@@ -6,10 +6,11 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpWrapperService, BddService } from 'common/service'; import { GenderResource, Gender, UUID } from 'app/back-api';
import { DataInterface, isArrayOf, isNullOrUndefined, TypeCheck } from 'common/utils'; import { RESTConfig } from 'app/back-api/rest-tools';
import { isNodeData, NodeData } from 'common/model'; import { environment } from 'environments/environment';
import { GenericInterfaceModelDB } from './GenericInterfaceModelDB'; import { GenericDataService } from './GenericDataService';
import { DataStore, SessionService } from '@kangaroo-and-rabbit/kar-cw';
export interface MessageLogIn { export interface MessageLogIn {
id: number; id: number;
@@ -18,109 +19,111 @@ export interface MessageLogIn {
} }
@Injectable() @Injectable()
export class GenderService extends GenericInterfaceModelDB { export class GenderService extends GenericDataService<Gender> {
getRestConfig(): RESTConfig {
constructor(http: HttpWrapperService, return {
bdd: BddService) { server: environment.server.karusic,
super('gender', http, bdd); token: this.session.getToken()
}
}
private lambdaGets(): Promise<Gender[]> {
return GenderResource.gets({ restConfig: this.getRestConfig() });
} }
constructor(private session: SessionService) {
super();
console.log('Start GenderService');
countTrack(id:number): Promise<number> { const self = this;
let self = this; this.setStore(new DataStore<Gender>(() => this.lambdaGets()));
}
insert(data: Gender): Promise<Gender> {
const self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('track') GenderResource.post({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ data
{ }).then((value: Gender) => {
check: TypeCheck.EQUAL, self.dataStore.updateValue(value);
key: 'typeId', resolve(value);
value: id, }).catch((error) => {
} ] ); reject(error);
resolve(data.length);
}).catch((response) => {
reject(response);
}); });
}); });
} }
patch(id: number, data: Gender): Promise<Gender> {
getSubTrack(id:number): Promise<NodeData[]> { const self = this;
let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('track') GenderResource.patch({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ params: {
{ id
check: TypeCheck.EQUAL,
key: 'typeId',
value: id,
}, {
check: TypeCheck.EQUAL,
key: 'artistId',
value: undefined,
}, {
check: TypeCheck.EQUAL,
key: 'playlistId',
value: undefined,
}, },
], [ 'name' ] ); data
resolve(data); }).then((value: Gender) => {
}).catch((response) => { self.dataStore.updateValue(value);
reject(response); resolve(value);
}).catch((error) => {
reject(error);
}); });
}); });
} }
getSubArtist(id:number): Promise<NodeData[]> { delete(id: number): Promise<void> {
let self = this; const self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('artist') GenderResource.remove({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ params: {
{ id
check: TypeCheck.EQUAL, }
key: 'parentId', }).then(() => {
value: id, self.dataStore.delete(id);
} ], resolve();
[ 'name' ]); }).catch((error) => {
resolve(data); reject(error);
}).catch((response) => {
reject(response);
}); });
}); });
} }
getSubPlaylist(id:number): Promise<NodeData[]> { deleteCover(id: number, coverId: UUID): Promise<Gender> {
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get('track') GenderResource.removeCover({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ params: {
{ id,
check: TypeCheck.EQUAL, coverId
key: 'typeId', }
value: id, }).then((value) => {
}, { self.dataStore.updateValue(value);
check: TypeCheck.EQUAL, resolve(value);
key: 'artistId', }).catch((error) => {
value: [undefined, null], reject(error);
}, { });
check: TypeCheck.NOT_EQUAL, });
key: 'playlistId', }
value: undefined, uploadCover(id: number,
file: File,
progress: any = null): Promise<Gender> {
let self = this;
return new Promise((resolve, reject) => {
GenderResource.uploadCover({
restConfig: this.getRestConfig(),
params: {
id,
}, },
]); data: {
//, [ 'universId' ]); file,
resolve(data); fileName: file.name
return; }
}).catch((response: any) => { }).then((value) => {
reject(response); self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
}); });
}); });
} }
} }

View File

@@ -5,45 +5,123 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { NodeData } from 'common/model';
import { HttpWrapperService, BddService } from 'common/service'; import { Playlist, PlaylistResource, UUID } from 'app/back-api';
import { DataInterface, TypeCheck } from 'common/utils'; import { RESTConfig } from 'app/back-api/rest-tools';
import { GenericInterfaceModelDB } from './GenericInterfaceModelDB'; import { environment } from 'environments/environment';
import { GenericDataService } from './GenericDataService';
import { SessionService, DataStore } from '@kangaroo-and-rabbit/kar-cw';
@Injectable() @Injectable()
export class PlaylistService extends GenericInterfaceModelDB { export class PlaylistService extends GenericDataService<Playlist> {
constructor(http: HttpWrapperService, getRestConfig(): RESTConfig {
bdd: BddService) { return {
super('playlist', http, bdd); server: environment.server.karusic,
token: this.session.getToken()
}
}
private lambdaGets(): Promise<Playlist[]> {
return PlaylistResource.gets({ restConfig: this.getRestConfig() });
} }
getSubArtist(id:number, select:Array<string> = []):any { constructor(private session: SessionService) {
super();
console.log('Start PlaylistService');
const self = this;
this.setStore(new DataStore<Playlist>(() => this.lambdaGets()));
}
getSubArtist(id: bigint, select: Array<string> = []): any {
// this.checkLocalBdd(); // this.checkLocalBdd();
} }
getSubTrack(id:number, select:Array<string> = []):any { getSubTrack(id: bigint, select: Array<string> = []): any {
// this.checkLocalBdd(); // this.checkLocalBdd();
} insert(data: Playlist): Promise<Playlist> {
const self = this;
return new Promise((resolve, reject) => {
PlaylistResource.post({
restConfig: this.getRestConfig(),
data
}).then((value: Playlist) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
});
});
}
patch(id: number, data: Playlist): Promise<Playlist> {
const self = this;
return new Promise((resolve, reject) => {
PlaylistResource.patch({
restConfig: this.getRestConfig(),
params: {
id
},
data
}).then((value: Playlist) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
});
});
} }
getAll(ids: number[]): Promise<NodeData[]> { delete(id: number): Promise<void> {
const self = this;
return new Promise((resolve, reject) => {
PlaylistResource.remove({
restConfig: this.getRestConfig(),
params: {
id
}
}).then(() => {
self.dataStore.delete(id);
resolve();
}).catch((error) => {
reject(error);
});
});
}
deleteCover(id: number, coverId: UUID): Promise<Playlist> {
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get(self.serviceName) PlaylistResource.removeCover({
.then((response: DataInterface) => { restConfig: this.getRestConfig(),
let data = response.getsWhere([ params: {
{ id,
check: TypeCheck.EQUAL, coverId
key: 'id', }
value: ids, }).then((value) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
});
});
}
uploadCover(id: number,
file: File,
progress: any = null): Promise<Playlist> {
let self = this;
return new Promise((resolve, reject) => {
PlaylistResource.uploadCover({
restConfig: this.getRestConfig(),
params: {
id,
}, },
], data: {
[ 'name', 'id' ]); file,
resolve(data); fileName: file.name
return; }
}).catch((response) => { }).then((value) => {
reject(response); self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
}); });
}); });
} }

View File

@@ -5,40 +5,125 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { isMedia, Media } from 'app/model';
import { NodeData } from 'common/model';
import { HttpWrapperService, BddService } from 'common/service'; import { RESTConfig } from 'app/back-api/rest-tools';
import { DataInterface, isArrayOf, isNullOrUndefined, TypeCheck } from 'common/utils'; import { environment } from 'environments/environment';
import { GenericInterfaceModelDB } from './GenericInterfaceModelDB'; import { Track, TrackResource, UUID } from 'app/back-api';
import { GenericDataService } from './GenericDataService';
import { TypeCheck, isArrayOf, isNumber, DataStore, DataTools, SessionService } from '@kangaroo-and-rabbit/kar-cw';
@Injectable() @Injectable()
export class TrackService extends GenericInterfaceModelDB { export class TrackService extends GenericDataService<Track> {
constructor(http: HttpWrapperService, getRestConfig(): RESTConfig {
bdd: BddService) { return {
super('track', http, bdd); server: environment.server.karusic,
token: this.session.getToken()
} }
get(id: number): Promise<Media> { }
private lambdaGets(): Promise<Track[]> {
return TrackResource.gets({ restConfig: this.getRestConfig() });
}
constructor(private session: SessionService) {
super();
console.log('Start TrackService');
const self = this;
this.setStore(new DataStore<Track>(() => this.lambdaGets()));
}
patch(id: number, data: Track): Promise<Track> {
const self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
super.get(id).then((data: NodeData) => { TrackResource.patch({
if (isMedia(data)) { restConfig: this.getRestConfig(),
resolve(data); params: {
return; id
} },
reject("model is wrong !!!") data
return }).then((value: Track) => {
}).catch((reason: any) => { self.dataStore.updateValue(value);
reject(reason); resolve(value);
}).catch((error) => {
reject(error);
}); });
}); });
} }
getWithAlbum(idAlbum: number): Promise<Media[]> {
delete(id: number): Promise<void> {
const self = this;
return new Promise((resolve, reject) => {
TrackResource.remove({
restConfig: this.getRestConfig(),
params: {
id
}
}).then(() => {
self.dataStore.delete(id);
resolve();
}).catch((error) => {
reject(error);
});
});
}
getTracksIdsForAlbums(idAlbums: number[]): Promise<number[]> {
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.bdd.get(self.serviceName) self.dataStore.getData()
.then((response: DataInterface) => { .then((response: Track[]) => {
let data = response.getsWhere([ let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.EQUAL,
key: 'albumId',
value: idAlbums,
},
],
['name']); // tODO : set the Id in the track ...
// filter with artist- ID !!!
const listId = DataTools.extractLimitOne(data, "id");
resolve(listId);
}).catch((response) => {
reject(response);
});
});
}
/**
* Get the number of track in this season ID
* @param AlbumId - Id of the album.
* @returns The number of element present in this season
*/
countTracksWithAlbumId(AlbumId: number): Promise<number> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: Track[]) => {
let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.EQUAL,
key: 'albumId',
value: AlbumId,
},
]);
resolve(data.length);
}).catch((response) => {
reject(response);
});
});
}
getTracksWithAlbumId(idAlbum: number): Promise<Track[]> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: Track[]) => {
let data = DataTools.getsWhere(response,
[
{ {
check: TypeCheck.EQUAL, check: TypeCheck.EQUAL,
key: 'albumId', key: 'albumId',
@@ -46,44 +131,245 @@ export class TrackService extends GenericInterfaceModelDB {
}, },
], ],
['track', 'name', 'id']); ['track', 'name', 'id']);
if (isArrayOf(data, isMedia)) {
resolve(data); resolve(data);
return; return;
}
reject("model is wrong !!!");
return;
}).catch((response) => { }).catch((response) => {
reject(response); reject(response);
}); });
}); });
} }
/**
getData(): Promise<Media[]> { * Get all the track for a specific artist
* @param idArtist - Id of the artist.
* @returns a promise on the list of track elements
*/
getTracksOfArtistWithNoAlbum(idArtist: number): Promise<Track[]> {
let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
super.getData().then((data: NodeData[]) => { self.gets()
if (isArrayOf(data, isMedia)) { .then((response: Track[]) => {
let data = DataTools.getsWhere(response, [
{
check: TypeCheck.CONTAINS,
key: 'artists',
value: idArtist,
}, {
check: TypeCheck.EQUAL,
key: 'albumId',
value: undefined,
},
],
['track', 'name']);
resolve(data);
}).catch((response) => {
reject(response);
});
});
}
/**
* Get all the track for a specific artist
* @param idArtist - Id of the artist.
* @returns a promise on the list of track elements
*/
getTracksOfAnArtist(idArtist: number): Promise<Track[]> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: Track[]) => {
let data = DataTools.getsWhere(response, [
{
check: TypeCheck.CONTAINS,
key: 'artists',
value: idArtist,
}
],
['track', 'name']);
resolve(data);
}).catch((response) => {
reject(response);
});
});
}
/**
* Get the number of track in this artist ID
* @param id - Id of the artist.
* @returns The number of track present in this artist
*/
countTracksOfAnArtist(artistId: number): Promise<number> {
let self = this;
return new Promise((resolve, reject) => {
self.getTracksOfAnArtist(artistId)
.then((response: Track[]) => {
resolve(response.length);
}).catch((error) => {
reject(error);
});
});
}
/**
* Get all the album of a specific artist
* @param artistId - ID of the artist
* @returns the required List.
*/
getAlbumIdsOfAnArtist(artistId: number): Promise<number[]> {
let self = this;
return new Promise((resolve, reject) => {
self.getTracksOfAnArtist(artistId)
.then((response: Track[]) => {
//console.log("==> get all tracks of the artist: " + JSON.stringify(data, null, 2));
// extract a single time all value "id" in an array
const listAlbumId = DataTools.extractLimitOne(response, "albumId");
if (isArrayOf(listAlbumId, isNumber)) {
resolve(listAlbumId);
} else {
reject(`Fail to get the ids (impossible case) ${listAlbumId}`);
}
}).catch((response) => {
reject(response);
});
});
}
countAlbumOfAnArtist(idArtist: number): Promise<number> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: Track[]) => {
//console.log(" <<<========================================>>> " + idArtist);
let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.CONTAINS, //< this is for array containing
key: 'artists',
value: idArtist,
},
], ['id']);
//console.log("==> get all tracks of the artist: " + JSON.stringify(data, null, 2));
// extract a single time all value "id" in an array
const listAlbumId = DataTools.extractLimitOne(data, "albumId");
resolve(listAlbumId.length);
}).catch((response) => {
reject(response);
});
});
}
countTrackForGender(typeId: number): Promise<number> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: Track[]) => {
let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.EQUAL,
key: 'typeId',
value: typeId,
}]);
resolve(data.length);
}).catch((response) => {
reject(response);
});
});
}
getTracksForGender(id: number): Promise<Track[]> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: Track[]) => {
let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.EQUAL,
key: 'genderId',
value: id,
}, {
check: TypeCheck.EQUAL,
key: 'artistId',
value: undefined,
}, {
check: TypeCheck.EQUAL,
key: 'playlistId',
value: undefined,
},
], ['name']);
resolve(data);
}).catch((response) => {
reject(response);
});
});
}
getSubPlaylist(typeId: number): Promise<Track[]> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
.then((response: Track[]) => {
let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.EQUAL,
key: 'typeId',
value: typeId,
}, {
check: TypeCheck.EQUAL,
key: 'artistId',
value: [undefined, null],
}, {
check: TypeCheck.NOT_EQUAL,
key: 'playlistId',
value: undefined,
},
]);
//, [ 'universId' ]);
resolve(data); resolve(data);
return; return;
} }).catch((response: any) => {
reject("model is wrong !!!") reject(response);
return
}).catch((reason: any) => {
reject(reason);
}); });
}); });
} }
uploadFile(file: File, uploadFile(file: File,
gender?: string, gender?: string,
artist?: string, artist?: string,
album?: string, album?: string,
trackId?: number, trackId?: number,
title?: string, title?: string,
progress: any = null) { progress: any = null): Promise<Track> {
const self = this;
return new Promise((resolve, reject) => {
TrackResource.uploadTrack({
restConfig: this.getRestConfig(),
data: {
fileName: file.name,
file,
gender: gender ?? null,
artist: artist ?? null,
album: album ?? null,
trackId: trackId ?? null,
title: title ?? null,
}
}).then((value: Track) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
});
});
}
/*
const formData = new FormData(); const formData = new FormData();
formData.append('fileName', file.name); formData.append('fileName', file.name);
// set the file at hte begining it will permit to abort the transmission // set the file at hte beginning it will permit to abort the transmission
formData.append('file', file ?? null); formData.append('file', file ?? null);
formData.append('gender', gender ?? null); formData.append('gender', gender ?? null);
formData.append('artist', artist ?? null); formData.append('artist', artist ?? null);
@@ -96,28 +382,44 @@ export class TrackService extends GenericInterfaceModelDB {
formData.append('title', title ?? null); formData.append('title', title ?? null);
return this.http.uploadMultipart(`${this.serviceName}/upload/`, formData, progress); return this.http.uploadMultipart(`${this.serviceName}/upload/`, formData, progress);
} */
uploadCoverBlob(blob: Blob, deleteCover(id: number, coverId: UUID): Promise<Track> {
mediaId: number,
progress: any = null) {
const formData = new FormData();
formData.append('fileName', 'take_screenshoot');
formData.append('typeId', mediaId.toString());
formData.append('file', blob);
let self = this; let self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
self.http.uploadMultipart(`${this.serviceName}/${mediaId}/add_cover/`, formData, progress) TrackResource.removeCover({
.then((response) => { restConfig: this.getRestConfig(),
let data = response; params: {
if (data === null || data === undefined) { id,
reject('error retrive data from server'); coverId
return;
} }
self.bdd.asyncSetInDB(self.serviceName, mediaId, data); }).then((value) => {
resolve(data); self.dataStore.updateValue(value);
}).catch((response) => { resolve(value);
reject(response); }).catch((error) => {
reject(error);
});
});
}
uploadCover(id: number,
file: File,
progress: any = null): Promise<Track> {
let self = this;
return new Promise((resolve, reject) => {
TrackResource.uploadCover({
restConfig: this.getRestConfig(),
params: {
id,
},
data: {
file,
fileName: file.name
}
}).then((value) => {
self.dataStore.updateValue(value);
resolve(value);
}).catch((error) => {
reject(error);
}); });
}); });
} }

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="256"
height="256"
viewBox="0 0 67.733333 67.733333"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="ikon_before_cut.svg"
inkscape:export-filename="/home/heero/dev/perso/appl_pro/NoKomment/plugin/chrome/ikon.png"
inkscape:export-xdpi="7.1250005"
inkscape:export-ydpi="7.1250005"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2">
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Drop Shadow"
id="filter5338"
x="-0.12319682"
y="-0.081815216"
width="1.2463936"
height="1.1636304">
<feFlood
flood-opacity="1"
flood-color="rgb(0,255,0)"
result="flood"
id="feFlood5328" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="in"
result="composite1"
id="feComposite5330" />
<feGaussianBlur
in="composite1"
stdDeviation="2.1"
result="blur"
id="feGaussianBlur5332" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset5334" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
result="composite2"
id="feComposite5336" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter1159"
x="-0.11802406"
width="1.2360481"
y="-0.078379973"
height="1.1567599">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="2.0118255"
id="feGaussianBlur1161" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Drop Shadow"
id="filter5338-3"
x="-0.12319682"
y="-0.081815216"
width="1.2463936"
height="1.1636304">
<feFlood
flood-opacity="1"
flood-color="rgb(0,255,0)"
result="flood"
id="feFlood5328-6" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="in"
result="composite1"
id="feComposite5330-7" />
<feGaussianBlur
in="composite1"
stdDeviation="2.1"
result="blur"
id="feGaussianBlur5332-5" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset5334-3" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
result="composite2"
id="feComposite5336-5" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="99.910714"
inkscape:cy="159.46429"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:snap-text-baseline="false"
inkscape:window-width="3838"
inkscape:window-height="2118"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid4504"
originx="0"
originy="0"
spacingy="1"
spacingx="1"
units="px"
visible="true" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26668)"
style="display:inline">
<g
id="text821-7"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:84.55024719px;line-height:1.25;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#2b3137;fill-opacity:1;stroke:none;stroke-width:2.11376619;stroke-opacity:1"
transform="matrix(0.8407653,0,0,0.83753055,-37.28971,3.4402954)"
aria-label="K">
<path
sodipodi:nodetypes="ccccccccccccc"
inkscape:connector-curvature="0"
id="path823-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:84.55024719px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:0.775;fill:#2b3137;fill-opacity:1;stroke-width:2.11376619;filter:url(#filter5338)"
d="m 65.200546,279.9533 h 8.949095 v 27.37877 l 25.568842,-27.37877 6.392207,6.84469 -20.455071,21.90302 20.455071,27.37876 -6.392207,5.47576 -19.176632,-27.37877 -6.39221,6.84469 v 20.53408 h -8.949095 z" />
</g>
<g
id="text821"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:84.55024719px;line-height:1.25;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#2b3137;fill-opacity:1;stroke:none;stroke-width:2.11376619;stroke-opacity:1;filter:url(#filter1159)"
transform="matrix(1.0347881,0,0,0.96638144,-54.239583,-37.041665)"
aria-label="K" />
<path
style="font-size:6.35px;line-height:1.25;font-family:SourceCodeVF;-inkscape-font-specification:'SourceCodeVF, @wght=700';font-variation-settings:'wght' 700;stroke-width:0.264583"
d="m 20.792125,274.01075 0.657068,-0.69832 -1.156264,-1.82907 c -0.23098,-0.35684 -0.504128,-0.77079 -0.753606,-1.14504 l 0.01741,-0.0185 c 0.388725,0.22626 0.827228,0.46447 1.197453,0.67332 l 1.89601,1.04288 0.678825,-0.72144 -3.893995,-1.89399 -0.770205,0.81857 z m -0.133728,-1.29418 1.357649,-1.44289 -0.52721,-0.49606 -1.35765,1.44289 z m 5.620896,-4.53751 0.639662,-0.67983 -1.08217,-1.01823 0.369873,-0.3931 c 0.600499,-0.6382 0.791609,-1.44363 0.102535,-2.092 -0.716822,-0.67447 -1.430518,-0.36075 -2.031017,0.27745 l -1.009535,1.07292 z m -0.983592,-2.20718 -0.846313,-0.79632 0.317655,-0.3376 c 0.335061,-0.35609 0.61494,-0.45895 0.915543,-0.17611 0.295978,0.2785 0.265831,0.61633 -0.06923,0.97243 z m 0.613106,0.0712 1.893491,0.51737 0.717988,-0.76307 -2.602349,-0.63505 z m 6.657254,-4.4343 c 0.691879,-0.73532 0.592495,-1.49148 -0.189072,-2.22687 l -1.854488,-1.74493 -0.622256,0.66133 1.923858,1.8102 c 0.360723,0.33941 0.424415,0.66091 0.154626,0.94764 -0.265438,0.2821 -0.585865,0.23346 -0.946589,-0.10596 l -1.923857,-1.8102 -0.644013,0.68445 1.854487,1.74493 c 0.781567,0.73539 1.559776,0.77011 2.247304,0.0394 z m 5.208675,-5.53571 c 0.700582,-0.74457 0.66647,-1.5701 0.162383,-2.04441 -0.425469,-0.40033 -0.905553,-0.38123 -1.423415,-0.12738 l -0.500729,0.22638 c -0.380781,0.18229 -0.63699,0.32486 -0.821976,0.1508 -0.175737,-0.16536 -0.124633,-0.405 0.08859,-0.63161 0.274141,-0.29135 0.535794,-0.40264 0.888574,-0.47177 l -0.108087,-0.74691 c -0.515716,0.0292 -0.993595,0.26833 -1.333007,0.62905 -0.617905,0.6567 -0.642274,1.47952 -0.142811,1.94948 0.439342,0.41338 0.980894,0.34748 1.423688,0.13635 l 0.53636,-0.23644 c 0.390031,-0.1736 0.610608,-0.30609 0.827967,-0.10157 0.147989,0.13924 0.128438,0.38242 -0.141352,0.66915 -0.278492,0.29597 -0.664444,0.45596 -1.071627,0.50879 l 0.101569,0.82796 c 0.586978,-0.0493 1.130948,-0.33091 1.513875,-0.73787 z m 4.191511,-4.56589 1.962501,-2.08572 -0.568833,-0.53523 -0.661419,0.70295 -1.872987,-1.76233 0.66142,-0.70295 -0.568833,-0.53523 -1.962501,2.08572 0.568833,0.53523 0.661419,-0.70295 1.872987,1.76234 -0.661419,0.70294 z m 6.50434,-6.80153 c 0.378575,-0.40235 0.548241,-0.87919 0.487514,-1.39844 l -0.764061,-0.0127 c 0.01799,0.29594 -0.041,0.57176 -0.245513,0.78912 -0.430793,0.45784 -1.083063,0.42828 -1.702767,-0.15482 -0.601205,-0.56568 -0.675007,-1.2193 -0.270323,-1.64939 0.204518,-0.21736 0.440062,-0.3009 0.709072,-0.31807 l -0.06838,-0.77058 c -0.394948,0.012 -0.871208,0.15679 -1.228026,0.53602 -0.761502,0.80931 -0.775216,1.98219 0.22371,2.92211 1.017424,0.95731 2.153837,0.80592 2.858771,0.0567 z"
id="text1"
aria-label="A R U S I C" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.1 KiB

Some files were not shown because too many files have changed in this diff Show More