Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Init

  • Loading branch information...
commit 28e8af5e678e61f3fb58826376be810905de1785 1 parent a9cf1fb
@longkerdandy authored
Showing with 12,762 additions and 0 deletions.
  1. +38 −0 medialibrary.api/pom.xml
  2. +48 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/core/MediaLibraryService.java
  3. +32 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/file/FileService.java
  4. +160 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/PersistenceService.java
  5. +243 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/entity/Movie.java
  6. +190 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/entity/MovieFile.java
  7. +119 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/entity/MovieImage.java
  8. +318 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/entity/MovieInfo.java
  9. +40 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/factory/MovieFactory.java
  10. +89 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/provider/MovieInfoProviderService.java
  11. +22 −0 medialibrary.api/src/main/java/org/chii2/medialibrary/api/shell/command/MediaLibraryCommand.java
  12. +61 −0 medialibrary.core/pom.xml
  13. +88 −0 medialibrary.core/src/main/java/org/chii2/medialibrary/MediaLibraryServiceImpl.java
  14. +648 −0 medialibrary.core/src/main/java/org/chii2/medialibrary/event/MovieHandler.java
  15. +68 −0 medialibrary.core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
  16. +50 −0 medialibrary.datasource/pom.xml
  17. +32 −0 medialibrary.datasource/src/main/resources/OSGI-INF/blueprint/blueprint.xml
  18. +67 −0 medialibrary.file/pom.xml
  19. +48 −0 medialibrary.file/src/main/java/org/chii2/medialibrary/file/FileExtensionFilter.java
  20. +92 −0 medialibrary.file/src/main/java/org/chii2/medialibrary/file/FileScanner.java
  21. +188 −0 medialibrary.file/src/main/java/org/chii2/medialibrary/file/FileServiceImpl.java
  22. +25 −0 medialibrary.file/src/main/resources/OSGI-INF/blueprint/blueprint.xml
  23. +91 −0 medialibrary.persistence/pom.xml
  24. +218 −0 medialibrary.persistence/src/main/java/org/chii2/medialibrary/persistence/PersistenceServiceImpl.java
  25. +207 −0 medialibrary.persistence/src/main/java/org/chii2/medialibrary/persistence/entity/MovieFileImpl.java
  26. +137 −0 medialibrary.persistence/src/main/java/org/chii2/medialibrary/persistence/entity/MovieImageImpl.java
  27. +488 −0 medialibrary.persistence/src/main/java/org/chii2/medialibrary/persistence/entity/MovieImpl.java
  28. +354 −0 medialibrary.persistence/src/main/java/org/chii2/medialibrary/persistence/entity/MovieInfoImpl.java
  29. +65 −0 medialibrary.persistence/src/main/java/org/chii2/medialibrary/persistence/factory/MovieFactoryImpl.java
  30. +27 −0 medialibrary.persistence/src/main/resources/META-INF/persistence.xml
  31. +35 −0 medialibrary.persistence/src/main/resources/OSGI-INF/blueprint/blueprint.xml
  32. +47 −0 medialibrary.shell/pom.xml
  33. +195 −0 medialibrary.shell/src/main/java/org/chii2/medialibrary/shell/command/MediaLibraryCommandImpl.java
  34. +28 −0 medialibrary.shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml
  35. +75 −0 medialibrary.tmdbprovider/pom.xml
  36. +312 −0 medialibrary.tmdbprovider/src/main/java/org/chii2/medialibrary/provider/tmdb/MovieInfoProviderServiceImpl.java
  37. +88 −0 medialibrary.tmdbprovider/src/main/java/org/chii2/medialibrary/provider/tmdb/handler/ImageResponseHandler.java
  38. +185 −0 medialibrary.tmdbprovider/src/main/java/org/chii2/medialibrary/provider/tmdb/handler/MovieResponseHandler.java
  39. +27 −0 medialibrary.tmdbprovider/src/main/java/org/chii2/medialibrary/provider/tmdb/parser/Parser.java
  40. +243 −0 medialibrary.tmdbprovider/src/main/java/org/chii2/medialibrary/provider/tmdb/parser/YamlParser.java
  41. +30 −0 medialibrary.tmdbprovider/src/main/resources/OSGI-INF/blueprint/blueprint.xml
  42. +43 −0 utility/pom.xml
  43. +122 −0 utility/src/main/java/org/chii2/util/ConfigUtils.java
  44. +256 −0 utility/src/main/java/regex2/ASCII.java
  45. +171 −0 utility/src/main/java/regex2/MatchResult.java
  46. +1,265 −0 utility/src/main/java/regex2/Matcher.java
  47. +5,281 −0 utility/src/main/java/regex2/Pattern.java
  48. +106 −0 utility/src/main/java/regex2/PatternSyntaxException.java
View
38 medialibrary.api/pom.xml
@@ -0,0 +1,38 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>chii2</artifactId>
+ <groupId>org.chii2</groupId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>chii2.medialibrary.api</artifactId>
+ <packaging>bundle</packaging>
+
+ <name>Chii2 Media Library Api</name>
+ <url>http://www.chii2.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>org.chii2.medialibrary.api.*</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
View
48 medialibrary.api/src/main/java/org/chii2/medialibrary/api/core/MediaLibraryService.java
@@ -0,0 +1,48 @@
+package org.chii2.medialibrary.api.core;
+
+import org.chii2.medialibrary.api.persistence.entity.Movie;
+
+import java.util.List;
+
+/**
+ * Media Library Core Interface, provide major functionality & operations.
+ */
+public interface MediaLibraryService {
+
+ /**
+ * Scan for all kinds of media files in directories.
+ * (Media type extensions and Directories are configured in configuration file)
+ */
+ public void scan();
+
+ /**
+ * Get all the Movies in the Media Library.
+ *
+ * @return Movie List
+ */
+ public List<? extends Movie> getAllMovies();
+
+ /**
+ * Get Movie by Movie ID
+ *
+ * @param id Movie ID
+ * @return Movie
+ */
+ public Movie getMovieById(String id);
+
+ /**
+ * Get all possible movie records by movie name
+ *
+ * @param movieName Movie Name
+ * @return Movie List
+ */
+ public List<? extends Movie> getAllMoviesByName(String movieName);
+
+ /**
+ * Get single movie record by movie name, usually return first result
+ *
+ * @param movieName Movie name
+ * @return Movie
+ */
+ public Movie getSingleMovieByName(String movieName);
+}
View
32 medialibrary.api/src/main/java/org/chii2/medialibrary/api/file/FileService.java
@@ -0,0 +1,32 @@
+package org.chii2.medialibrary.api.file;
+
+import java.util.List;
+
+/**
+ * FileService provide watcher and scanner functionality
+ */
+public interface FileService {
+
+ // Event Topic for movie scan
+ public final static String MOVIE_SCAN_TOPIC = "org/chii2/medialibrary/file/movie/SCAN";
+
+ /**
+ * Scan default directories (from configuration) for movies files
+ */
+ public void scanMovies();
+
+ /**
+ * Scan directories for movie files
+ *
+ * @param directories Directories to be scanned
+ */
+ public void scanMovies(List<String> directories);
+
+ /**
+ * Scan directories for movie files
+ *
+ * @param directories Directories to be scanned
+ * @param extensions File extensions to be accepted, like " .avi .mkv "
+ */
+ public void scanMovies(List<String> directories, List<String> extensions);
+}
View
160 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/PersistenceService.java
@@ -0,0 +1,160 @@
+package org.chii2.medialibrary.api.persistence;
+
+import org.chii2.medialibrary.api.persistence.entity.Movie;
+import org.chii2.medialibrary.api.persistence.entity.MovieFile;
+import org.chii2.medialibrary.api.persistence.entity.MovieImage;
+import org.chii2.medialibrary.api.persistence.entity.MovieInfo;
+
+import java.util.List;
+
+/**
+ * Persistence layer for media library
+ */
+public interface PersistenceService {
+
+ /**
+ * Get all the movie records from database
+ *
+ * @return List of movie records
+ */
+ public List<? extends Movie> getAllMovies();
+
+ /**
+ * Get Movie by Movie ID
+ *
+ * @param id Movie ID
+ * @return Movie
+ */
+ public Movie getMovieById(String id);
+
+ /**
+ * Get all possible movie records by movie name
+ *
+ * @param movieName Movie Name
+ * @return Movie List
+ */
+ public List<? extends Movie> getAllMoviesByName(String movieName);
+
+ /**
+ * Get single movie record by movie name, usually return first result
+ *
+ * @param movieName Movie name
+ * @return Movie
+ */
+ public Movie getSingleMovieByName(String movieName);
+
+ /**
+ * Get movie file by id
+ *
+ * @param id Movie file id
+ * @return Movie file
+ */
+ public MovieFile getMovieFileById(String id);
+
+ /**
+ * Get movie Information by id
+ *
+ * @param id Movie information id
+ * @return Movie information
+ */
+ public MovieInfo getMovieInfoById(String id);
+
+ /**
+ * Get Movie Image by Image ID
+ *
+ * @param imageId Movie Image ID
+ * @return Image
+ */
+ public MovieImage getMovieImageById(String imageId);
+
+ /**
+ * Persist a list of movies into database
+ *
+ * @param movies List of movies
+ */
+ public void persist(List<Movie> movies);
+
+ /**
+ * Persist a movie into database
+ *
+ * @param movie Movie
+ */
+ public void persist(Movie movie);
+
+ /**
+ * Persist a movie file into database
+ *
+ * @param movieFile Movie file
+ */
+ public void persist(MovieFile movieFile);
+
+ /**
+ * Persist a movie information into database
+ *
+ * @param movieInfo Movie information
+ */
+ public void persist(MovieInfo movieInfo);
+
+ /**
+ * Persist a movie image into database
+ *
+ * @param movieImage Movie image
+ */
+ public void persist(MovieImage movieImage);
+
+ /**
+ * Merge a movie into database
+ *
+ * @param movie Movie
+ */
+ public void merge(Movie movie);
+
+ /**
+ * Merge a movie file into database
+ *
+ * @param movieFile Movie File
+ */
+ public void merge(MovieFile movieFile);
+
+ /**
+ * Merge a movie information into database
+ *
+ * @param movieInfo Movie information
+ */
+ public void merge(MovieInfo movieInfo);
+
+ /**
+ * Merge a movie image into database
+ *
+ * @param movieImage Movie Image
+ */
+ public void merge(MovieImage movieImage);
+
+ /**
+ * Remove a movie from database
+ *
+ * @param movie Movie
+ */
+ public void remove(Movie movie);
+
+ /**
+ * Remove a movie file from database
+ *
+ * @param movieFile Movie File
+ */
+ public void remove(MovieFile movieFile);
+
+ /**
+ * Remove a movie information from database
+ *
+ * @param movieInfo Movie Information
+ */
+ public void remove(MovieInfo movieInfo);
+
+ /**
+ * Remove a movie image from database
+ *
+ * @param movieImage Movie Image
+ */
+ public void remove(MovieImage movieImage);
+}
View
243 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/entity/Movie.java
@@ -0,0 +1,243 @@
+package org.chii2.medialibrary.api.persistence.entity;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Represent a movie (which may contains multiple files, like disk1 and disk2)
+ */
+public interface Movie {
+
+ /**
+ * Get the id
+ *
+ * @return id Id
+ */
+ public String getId();
+
+ /**
+ * Set the id
+ *
+ * @param id Id
+ */
+ public void setId(String id);
+
+ /**
+ * Get list of movie files
+ *
+ * @return Movie files
+ */
+ public List<? extends MovieFile> getFiles();
+
+ /**
+ * Set list of movie files
+ *
+ * @param files Movie files
+ */
+ public void setFiles(List<MovieFile> files);
+
+ /**
+ * Get number of files included
+ *
+ * @return Files count
+ */
+ public int getFilesCount();
+
+ /**
+ * Add a movie file
+ *
+ * @param file Movie file
+ */
+ public void addFile(MovieFile file);
+
+ /**
+ * Remove a movie file
+ *
+ * @param file Movie file
+ */
+ public void removeFile(MovieFile file);
+
+ /**
+ * Test whether a MovieFile belongs to this Movie group
+ *
+ * @param file MovieFile
+ * @return True if it should be included to this Movie group
+ */
+ public boolean shouldIncl(MovieFile file);
+
+ /**
+ * Get the file id by a file's absolute name
+ *
+ * @param absoluteName Absolute file name
+ * @return File id, Null if not found
+ */
+ public String getFileIdByName(String absoluteName);
+
+ /**
+ * Get movie name from file name
+ *
+ * @return Movie name
+ */
+ public String getGuessedMovieName();
+
+ /**
+ * Get movie release year from file name
+ *
+ * @return Movie Year
+ */
+ public String getGuessedMovieYear();
+
+ /**
+ * Get movie source from file name
+ *
+ * @return Movie source
+ */
+ public String getMovieSource();
+
+ /**
+ * Get movie resolution from file name
+ *
+ * @return Movie resolution
+ */
+ public String getMovieResolution();
+
+ /**
+ * Get movie codec (video codec + audio codec) from file name
+ *
+ * @return Movie codec
+ */
+ public String getMovieCodec();
+
+ /**
+ * Get movie video codec from file name
+ *
+ * @return Movie codec
+ */
+ public String getMovieVideoCodec();
+
+ /**
+ * Get movie audio codec from file name
+ *
+ * @return Movie codec
+ */
+ public String getMovieAudioCodec();
+
+ /**
+ * Get movie format (file extension) from file name
+ *
+ * @return Movie format
+ */
+ public String getMovieFormat();
+
+ /**
+ * Get movie release group (0day group) from file name
+ *
+ * @return Movie release group
+ */
+ public String getMovieReleaseGroup();
+
+ /**
+ * Get list of movie information
+ *
+ * @return Movie information
+ */
+ public List<? extends MovieInfo> getInfo();
+
+ /**
+ * Set list of movie information
+ *
+ * @param info Movie information
+ */
+ public void setInfo(List<MovieInfo> info);
+
+ /**
+ * Get movie information count
+ *
+ * @return Count
+ */
+ public int getInfoCount();
+
+ /**
+ * Add a new movie information
+ *
+ * @param info Movie information
+ */
+ public void addInfo(MovieInfo info);
+
+ /**
+ * Remove a movie information
+ *
+ * @param info Movie information
+ */
+ public void removeInfo(MovieInfo info);
+
+ /**
+ * Get movie name from provider
+ *
+ * @return Movie name
+ */
+ public String getMovieName();
+
+ /**
+ * Get movie year from provider
+ *
+ * @return Movie year
+ */
+ public String getMovieYear();
+
+ /**
+ * Get movie original name from provider
+ *
+ * @return Movie original name
+ */
+ public String getMovieOriginalName();
+
+ /**
+ * Get movie alternative name from provider
+ *
+ * @return Movie alternative name
+ */
+ public String getMovieAlternativeName();
+
+ /**
+ * Get movie provider name
+ *
+ * @return Movie provider name
+ */
+ public String getProviderName();
+
+ /**
+ * Get movie votes from provider
+ *
+ * @return Movie votes
+ */
+ public int getMovieVotes();
+
+ /**
+ * Get movie rating from provider
+ *
+ * @return Movie rating
+ */
+ public double getMovieRating();
+
+ /**
+ * Get movie certification from provider
+ *
+ * @return Movie certification
+ */
+ public String getMovieCertification();
+
+ /**
+ * Get movie overview from provider
+ *
+ * @return Movie overview
+ */
+ public String getMovieOverview();
+
+ /**
+ * Get movie released date
+ *
+ * @return Movie released date
+ */
+ public Date getMovieReleasedDate();
+}
View
190 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/entity/MovieFile.java
@@ -0,0 +1,190 @@
+package org.chii2.medialibrary.api.persistence.entity;
+
+/**
+ * Represent a movie file on the disk
+ */
+public interface MovieFile {
+
+ /**
+ * Get the id
+ *
+ * @return id
+ */
+ public String getId();
+
+ /**
+ * Set the id
+ *
+ * @param id
+ */
+ public void setId(String id);
+
+ /**
+ * Get Movie File Name
+ *
+ * @return File Name
+ */
+ public String getFileName();
+
+ /**
+ * Set Movie File Name
+ *
+ * @param fileName File Name
+ */
+ public void setFileName(String fileName);
+
+ /**
+ * Get Movie File Path (Directory)
+ *
+ * @return File Path (Directory)
+ */
+ public String getFilePath();
+
+ /**
+ * Set Movie File Path (Directory)
+ *
+ * @param filePath Movie File Path (Directory)
+ */
+ public void setFilePath(String filePath);
+
+ /**
+ * Get Movie Absolute File Name (Including Path)
+ *
+ * @return Absolute File Name (Including Path)
+ */
+ public String getAbsoluteName();
+
+ /**
+ * Set Movie Absolute File Name (Including Path)
+ *
+ * @param absoluteName Absolute File Name (Including Path)
+ */
+ public void setAbsoluteName(String absoluteName);
+
+ /**
+ * Get Movie Name (Guessed from File Name)
+ *
+ * @return Movie Name
+ */
+ public String getMovieName();
+
+ /**
+ * Set Movie Name (Guessed from File Name)
+ *
+ * @param movieName Movie Name
+ */
+ public void setMovieName(String movieName);
+
+ /**
+ * Get Movie Release Year (Guessed from File Name)
+ *
+ * @return Year
+ */
+ public String getYear();
+
+ /**
+ * Set Movie Release Year (Guessed from File Name)
+ *
+ * @param year Movie Release Year
+ */
+ public void setYear(String year);
+
+ /**
+ * Get Movie Source (Guessed from File Name)
+ *
+ * @return Movie Source
+ */
+ public String getSource();
+
+ /**
+ * Set Movie Source (Guessed from File Name)
+ *
+ * @param source Movie Source
+ */
+ public void setSource(String source);
+
+ /**
+ * Get Movie Resolution (Guessed from File Name)
+ *
+ * @return Movie Resolution
+ */
+ public String getResolution();
+
+ /**
+ * Set Movie Resolution (Guessed from File Name)
+ *
+ * @param resolution Movie Resolution
+ */
+ public void setResolution(String resolution);
+
+ /**
+ * Get Movie Video Codec (Guessed from File Name)
+ *
+ * @return Movie Video Codec
+ */
+ public String getVideoCodec();
+
+ /**
+ * Set Movie Video Codec (Guessed from File Name)
+ *
+ * @param videoCodec Movie Video Codec
+ */
+ public void setVideoCodec(String videoCodec);
+
+ /**
+ * Get Movie Audio Codec (Guessed from File Name)
+ *
+ * @return Movie Audio Codec
+ */
+ public String getAudioCodec();
+
+ /**
+ * Set Movie Audio Codec (Guessed from File Name)
+ *
+ * @param audioCodec Movie Audio Codec
+ */
+ public void setAudioCodec(String audioCodec);
+
+ /**
+ * Get Movie Release Group (Guessed from File Name)
+ *
+ * @return Movie Release Group
+ */
+ public String getGroup();
+
+ /**
+ * Set Movie Release Group (Guessed from File Name)
+ *
+ * @param group Movie Release Group
+ */
+ public void setGroup(String group);
+
+ /**
+ * Get Movie Disk Number (Guessed from File Name)
+ *
+ * @return Movie Disk Number
+ */
+ public int getDiskNum();
+
+ /**
+ * Set Movie Disk Number (Guessed from File Name)
+ *
+ * @param diskNum Movie Disk Number
+ */
+ public void setDiskNum(int diskNum);
+
+ /**
+ * Get Movie File Extension
+ *
+ * @return Movie File Extension
+ */
+ public String getFileExtension();
+
+ /**
+ * Set Movie File Extension
+ *
+ * @param fileExtension Movie File Extension
+ */
+ public void setFileExtension(String fileExtension);
+
+}
View
119 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/entity/MovieImage.java
@@ -0,0 +1,119 @@
+package org.chii2.medialibrary.api.persistence.entity;
+
+/**
+ * Represent Movie Poster
+ */
+public interface MovieImage {
+
+ /**
+ * Get ID
+ *
+ * @return ID
+ */
+ public String getId();
+
+ /**
+ * Set ID
+ *
+ * @param id ID
+ */
+ public void setId(String id);
+
+ /**
+ * Get Image Type (Poster Backdrop)
+ *
+ * @return Type
+ */
+ public String getType();
+
+ /**
+ * Set Image Type
+ *
+ * @param type Type
+ */
+ public void setType(String type);
+
+ /**
+ * Get Image Size
+ *
+ * @return Size
+ */
+ public String getSize();
+
+ /**
+ * Set Image Size
+ *
+ * @param size
+ */
+ public void setSize(String size);
+
+ /**
+ * Get Image Height
+ *
+ * @return Height
+ */
+ public int getHeight();
+
+ /**
+ * Set Image Height
+ *
+ * @param height Height
+ */
+ public void setHeight(int height);
+
+ /**
+ * Get Image Width
+ *
+ * @return Width
+ */
+ public int getWidth();
+
+ /**
+ * Set Image Width
+ *
+ * @param width Width
+ */
+ public void setWidth(int width);
+
+ /**
+ * Get Image URL
+ *
+ * @return URL
+ */
+ public String getUrl();
+
+ /**
+ * Set Image URL
+ *
+ * @param url URL
+ */
+ public void setUrl(String url);
+
+ /**
+ * Get Image Provider ID
+ *
+ * @return Provider ID
+ */
+ public String getProviderId();
+
+ /**
+ * Set Image Provider ID
+ *
+ * @param providerId
+ */
+ public void setProviderId(String providerId);
+
+ /**
+ * Get the real Image
+ *
+ * @return Image
+ */
+ public byte[] getImage();
+
+ /**
+ * Set the real Image
+ *
+ * @param image Image
+ */
+ public void setImage(byte[] image);
+}
View
318 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/entity/MovieInfo.java
@@ -0,0 +1,318 @@
+package org.chii2.medialibrary.api.persistence.entity;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Represent Movie Information
+ */
+public interface MovieInfo {
+
+ /**
+ * Get ID
+ *
+ * @return ID
+ */
+ public String getId();
+
+ /**
+ * Set ID
+ *
+ * @param id ID
+ */
+ public void setId(String id);
+
+ /**
+ * Get Movie Score
+ *
+ * @return Score
+ */
+ public double getScore();
+
+ /**
+ * Set Movie Score
+ *
+ * @param score Score
+ */
+ public void setScore(double score);
+
+ /**
+ * Get Movie Popularity
+ *
+ * @return Popularity
+ */
+ public int getPopularity();
+
+ /**
+ * Set Movie Popularity
+ *
+ * @param popularity Popularity
+ */
+ public void setPopularity(int popularity);
+
+ /**
+ * Whether is Adult
+ *
+ * @return True if is Adult
+ */
+ public boolean isAdult();
+
+ /**
+ * Set whether is Adult
+ *
+ * @param adult True if is Adult
+ */
+ public void setAdult(boolean adult);
+
+ /**
+ * Get Movie Language
+ *
+ * @return Language
+ */
+ public String getLanguage();
+
+ /**
+ * Set Movie Language
+ *
+ * @param language Language
+ */
+ public void setLanguage(String language);
+
+ /**
+ * Get Movie Original Name
+ *
+ * @return Original Name
+ */
+ public String getOriginalName();
+
+ /**
+ * Set Movie Original Name
+ *
+ * @param originalName Original Name
+ */
+ public void setOriginalName(String originalName);
+
+ /**
+ * Get Movie Name
+ *
+ * @return name
+ */
+ public String getName();
+
+ /**
+ * Set Movie Name
+ *
+ * @param name Name
+ */
+ public void setName(String name);
+
+ /**
+ * Get Alternative Movie Name
+ *
+ * @return Alternative Movie Name
+ */
+ public String getAlternativeName();
+
+ /**
+ * Set Alternative Movie Name
+ *
+ * @param alternativeName Alternative Movie Name
+ */
+ public void setAlternativeName(String alternativeName);
+
+ /**
+ * Get Provider ID
+ *
+ * @return Provider ID
+ */
+ public String getProviderId();
+
+ /**
+ * Set Provider ID
+ *
+ * @param providerId Provider ID
+ */
+ public void setProviderId(String providerId);
+
+ /**
+ * Get Provider Name (TMDb)
+ *
+ * @return Provider Name (TMDb)
+ */
+ public String getProviderName();
+
+ /**
+ * Set Provider Name (TMDb)
+ *
+ * @param providerName Provider Name (TMDb)
+ */
+ public void setProviderName(String providerName);
+
+ /**
+ * Get IMDb ID
+ *
+ * @return IMDb ID
+ */
+ public String getIMDbId();
+
+ /**
+ * Set IMDb ID
+ *
+ * @param imdbId IMDb ID
+ */
+ public void setIMDbId(String imdbId);
+
+ /**
+ * Get Provider URL for this movie
+ *
+ * @return Provider URL
+ */
+ public String getUrl();
+
+ /**
+ * Set Provider URL for this movie
+ *
+ * @param url Provider URL
+ */
+ public void setUrl(String url);
+
+ /**
+ * Get Movie Votes Count
+ *
+ * @return Movie Votes
+ */
+ public int getVotes();
+
+ /**
+ * Set Movie Votes Count
+ *
+ * @param votes Movie Votes
+ */
+ public void setVotes(int votes);
+
+ /**
+ * Get Movie Rating
+ *
+ * @return Movie Rating
+ */
+ public double getRating();
+
+ /**
+ * Set Movie Rating
+ *
+ * @param rating Movie Rating
+ */
+ public void setRating(double rating);
+
+ /**
+ * Get Movie Certification
+ *
+ * @return Movie Certification
+ */
+ public String getCertification();
+
+ /**
+ * Set Movie Certification
+ *
+ * @param certification Movie Certification
+ */
+ public void setCertification(String certification);
+
+ /**
+ * Get Movie Overview
+ *
+ * @return Movie Overview
+ */
+ public String getOverview();
+
+ /**
+ * Set Movie Overview
+ *
+ * @param overview Movie Overview
+ */
+ public void setOverview(String overview);
+
+ /**
+ * Get Movie Released Date
+ *
+ * @return Movie Released Date
+ */
+ public Date getReleasedDate();
+
+ /**
+ * Set Movie Released Date
+ *
+ * @param releasedDate Movie Released Date
+ */
+ public void setReleasedDate(Date releasedDate);
+
+ /**
+ * Get Provider Information Version
+ *
+ * @return Version
+ */
+ public int getVersion();
+
+ /**
+ * Set Provider Information Version
+ *
+ * @param version Version
+ */
+ public void setVersion(int version);
+
+ /**
+ * Get Last Modified Date
+ *
+ * @return Last Modified Date
+ */
+ public Date getLastModified();
+
+ /**
+ * Set Last Modified Date
+ *
+ * @param lastModified Last Modified Date
+ */
+ public void setLastModified(Date lastModified);
+
+ /**
+ * Get Movie Images
+ *
+ * @return Movie Images
+ */
+ public List<? extends MovieImage> getImages();
+
+ /**
+ * Get Movie Posters
+ *
+ * @return Movie Posters
+ */
+ public List<? extends MovieImage> getPosters();
+
+ /**
+ * Get Movie Images Count
+ *
+ * @return Count of Images
+ */
+ public int getImagesCount();
+
+ /**
+ * Get Movie Posters Count
+ *
+ * @return Count of Posters
+ */
+ public int getPostersCount();
+
+ /**
+ * Add a Movie Image
+ *
+ * @param image Movie Image
+ */
+ public void addImage(MovieImage image);
+
+ /**
+ * Remove a Movie Image
+ *
+ * @param image Movie Image
+ */
+ public void removeImage(MovieImage image);
+}
View
40 medialibrary.api/src/main/java/org/chii2/medialibrary/api/persistence/factory/MovieFactory.java
@@ -0,0 +1,40 @@
+package org.chii2.medialibrary.api.persistence.factory;
+
+import org.chii2.medialibrary.api.persistence.entity.Movie;
+import org.chii2.medialibrary.api.persistence.entity.MovieFile;
+import org.chii2.medialibrary.api.persistence.entity.MovieImage;
+import org.chii2.medialibrary.api.persistence.entity.MovieInfo;
+
+/**
+ * Movie Factory
+ */
+public interface MovieFactory {
+
+ /**
+ * Create a new Movie instance
+ *
+ * @return new Movie instance
+ */
+ public Movie createMovie();
+
+ /**
+ * Create a new MovieFile instance
+ *
+ * @return new MovieFile instance
+ */
+ public MovieFile createMovieFile();
+
+ /**
+ * Create a new MovieInfo instance
+ *
+ * @return new MovieInfo instance
+ */
+ public MovieInfo createMovieInfo();
+
+ /**
+ * Create a new MovieImage instance
+ *
+ * @return new MovieImage instance
+ */
+ public MovieImage createMovieImage();
+}
View
89 medialibrary.api/src/main/java/org/chii2/medialibrary/api/provider/MovieInfoProviderService.java
@@ -0,0 +1,89 @@
+package org.chii2.medialibrary.api.provider;
+
+import java.util.List;
+
+/**
+ * Movie Information Provider Service, each provider can provide movie information by download from internet or something else
+ */
+public interface MovieInfoProviderService {
+
+ // Event Topic for movie information provided
+ public final static String MOVIE_INFO_PROVIDED_TOPIC = "org/chii2/medialibrary/provider/movie/INFO_PROVIDED";
+ // Event Topic for movie information failed
+ public final static String MOVIE_INFO_FAILED_TOPIC = "org/chii2/medialibrary/provider/movie/INFO_FAILED";
+ // Movie ID property key in the movie info provided events
+ public final static String MOVIE_ID_PROPERTY = "movie_id";
+ // Movie Name property key in the movie info provided events
+ public final static String MOVIE_NAME_PROPERTY = "movie_name";
+ // Movie Year property key in the movie info provided events
+ public final static String MOVIE_YEAR_PROPERTY = "movie_year";
+ // Exclude providers property key in the movie info provided events
+ public final static String EXCLUDE_PROVIDERS_PROPERTY = "exclude_providers";
+ // Movie information property key in the movie info provided events
+ public final static String MOVIE_INFO_PROPERTY = "movie_info";
+
+ // Event Topic for movie image provided
+ public final static String MOVIE_IMAGE_PROVIDED_TOPIC = "org/chii2/medialibrary/provider/movie/IMAGE_PROVIDED";
+ // Image ID property key in the image provided events
+ public final static String IMAGE_ID_PROPERTY = "image_id";
+ // Image picture property key in the image provide events
+ public final static String IMAGE_CONTENT_PROPERTY = "image_content";
+
+ /**
+ * Get the provider name
+ *
+ * @return Provider name
+ */
+ public String getProviderName();
+
+ /**
+ * Get movie information by movie name. This usually done by searching the movie name and fetch the first result.
+ * This should be done in a asynchronous way
+ *
+ * @param movieId Movie Id
+ * @param movieName Movie Name (Guessed Name)
+ * @param excludeProviders Exclude Movie Providers (Which may already failed)
+ */
+ public void getMovieInformationByName(String movieId, String movieName, List<String> excludeProviders);
+
+ /**
+ * Get movie information by movie name and use year to narrow result. This usually done by searching the movie name and fetch the first result.
+ * This should be done in a asynchronous way
+ *
+ * @param movieId Movie Id
+ * @param movieName Movie Name (Guessed Name)
+ * @param movieYear Movie Year (Guessed Year)
+ * @param excludeProviders Exclude Movie Providers (Which may already failed)
+ */
+ public void getMovieInformationByName(String movieId, String movieName, String movieYear, List<String> excludeProviders);
+
+ /**
+ * Get movie information by movie name. This usually done by searching the movie name and fetch all possible results.
+ * This should be done in a asynchronous way
+ *
+ * @param movieId Movie Id
+ * @param movieName Movie Name (Guessed Name)
+ * @param excludeProviders Exclude Movie Providers (Which may already failed)
+ */
+ public void getAllMovieInformationByName(String movieId, String movieName, List<String> excludeProviders);
+
+ /**
+ * Get movie information by movie name and use year to narrow result. This usually done by searching the movie name and fetch all possible results.
+ * This should be done in a asynchronous way
+ *
+ * @param movieId Movie Id
+ * @param movieName Movie Name (Guessed Name)
+ * @param movieYear Movie Year (Guessed Year)
+ * @param excludeProviders Exclude Movie Providers (Which may already failed)
+ */
+ public void getAllMovieInformationByName(String movieId, String movieName, String movieYear, List<String> excludeProviders);
+
+ /**
+ * Get Movie Image from image url.
+ * This should be done in a asynchronous way.
+ *
+ * @param imageId Image ID
+ * @param url Image URI
+ */
+ public void getMovieImageByUrl(String imageId, String url);
+}
View
22 medialibrary.api/src/main/java/org/chii2/medialibrary/api/shell/command/MediaLibraryCommand.java
@@ -0,0 +1,22 @@
+package org.chii2.medialibrary.api.shell.command;
+
+import java.util.List;
+
+/**
+ * Media Library Shell Command
+ */
+public interface MediaLibraryCommand {
+ /**
+ * Command scan, scan all kinds of media and save them in library, this may also trigger information update from providers
+ *
+ * @param media Media type, currently supported type are: <movies>
+ */
+ public void scan(String media);
+
+ /**
+ * Command show, show all kinds of media in chii2 media library
+ *
+ * @param arguments Show command arguments, currently support arguments are: <movies>
+ */
+ public void show(String[] arguments);
+}
View
61 medialibrary.core/pom.xml
@@ -0,0 +1,61 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>chii2</artifactId>
+ <groupId>org.chii2</groupId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>chii2.medialibrary.core</artifactId>
+ <packaging>bundle</packaging>
+
+ <name>Chii2 Media Library Core</name>
+ <url>http://www.chii2.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.chii2</groupId>
+ <artifactId>chii2.medialibrary.api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.chii2</groupId>
+ <artifactId>chii2.utility</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.eventadmin</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>org.chii2.medialibrary,org.chii2.medialibrary.event</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
View
88 medialibrary.core/src/main/java/org/chii2/medialibrary/MediaLibraryServiceImpl.java
@@ -0,0 +1,88 @@
+package org.chii2.medialibrary;
+
+import org.chii2.medialibrary.api.core.MediaLibraryService;
+import org.chii2.medialibrary.api.file.FileService;
+import org.chii2.medialibrary.api.persistence.entity.Movie;
+import org.chii2.medialibrary.api.persistence.PersistenceService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Media Library Core Interface, provide major functionality & operations.
+ */
+public class MediaLibraryServiceImpl implements MediaLibraryService {
+
+ // Persistence Service
+ private PersistenceService persistenceService;
+ // File Service
+ private FileService fileService;
+ // Logger
+ private Logger logger;
+
+ public MediaLibraryServiceImpl() {
+ logger = LoggerFactory.getLogger("org.chii2.medialibrary.core");
+ }
+
+ /**
+ * Life Cycle Init
+ */
+ @SuppressWarnings("unused")
+ public void init() {
+ logger.debug("Chii2 Media Library MediaLibraryService (Core) init.");
+ }
+
+ /**
+ * Life Cycle Destroy
+ */
+ @SuppressWarnings("unused")
+ public void destroy() {
+ logger.debug("Chii2 Media Library MediaLibraryService (Core) destroy.");
+ }
+
+ @Override
+ public void scan() {
+ fileService.scanMovies();
+ }
+
+ @Override
+ public List<? extends Movie> getAllMovies() {
+ return persistenceService.getAllMovies();
+ }
+
+ @Override
+ public Movie getMovieById(String id) {
+ return persistenceService.getMovieById(id);
+ }
+
+ @Override
+ public List<? extends Movie> getAllMoviesByName(String movieName) {
+ return persistenceService.getAllMoviesByName(movieName);
+ }
+
+ @Override
+ public Movie getSingleMovieByName(String movieName) {
+ return persistenceService.getSingleMovieByName(movieName);
+ }
+
+ /**
+ * Inject PersistenceService
+ *
+ * @param persistenceService PersistenceService
+ */
+ @SuppressWarnings("unused")
+ public void setPersistenceService(PersistenceService persistenceService) {
+ this.persistenceService = persistenceService;
+ }
+
+ /**
+ * Inject FileService
+ *
+ * @param fileService FileService
+ */
+ @SuppressWarnings("unused")
+ public void setFileService(FileService fileService) {
+ this.fileService = fileService;
+ }
+}
View
648 medialibrary.core/src/main/java/org/chii2/medialibrary/event/MovieHandler.java
@@ -0,0 +1,648 @@
+package org.chii2.medialibrary.event;
+
+import org.chii2.medialibrary.api.file.FileService;
+import org.chii2.medialibrary.api.persistence.PersistenceService;
+import org.chii2.medialibrary.api.persistence.entity.Movie;
+import org.chii2.medialibrary.api.persistence.entity.MovieFile;
+import org.chii2.medialibrary.api.persistence.entity.MovieImage;
+import org.chii2.medialibrary.api.persistence.entity.MovieInfo;
+import org.chii2.medialibrary.api.persistence.factory.MovieFactory;
+import org.chii2.medialibrary.api.provider.MovieInfoProviderService;
+import org.chii2.util.ConfigUtils;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.event.EventHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import regex2.Matcher;
+import regex2.Pattern;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Movie Event Handler handle all kinds of event related to movies.
+ */
+public class MovieHandler implements EventHandler {
+
+ // Injected ConfigAdmin Service
+ private ConfigurationAdmin configAdmin;
+ // Injected EventAdmin Service
+ private EventAdmin eventAdmin;
+ // Injected Persistence Service
+ private PersistenceService persistenceService;
+ // Injected MovieFactory
+ private MovieFactory movieFactory;
+ // Injected list of Movie Information Provider Service
+ private List<MovieInfoProviderService> providerServices;
+ // Movie File Patterns
+ private List<Pattern> moviePatterns = new ArrayList<Pattern>() {{
+ add(Pattern.compile("^(?<name>[\\w\\.\\-\\']+)\\.\\(?(?<year>\\d{4})\\)?(?<info>(\\.\\w+)+)\\-\\[?(?<group>\\w+)\\]?\\.((?<disk>\\w+)\\.)?(?<ext>[\\w\\-]+)$", Pattern.CASE_INSENSITIVE));
+ }};
+ // Movie Name Separator Pattern
+ private Pattern movieSeparatorPattern = Pattern.compile("[\\._]", Pattern.CASE_INSENSITIVE);
+ // Movie Source Pattern
+ private Pattern movieSourcePattern = Pattern.compile("(?<source>BDRip|BluRay|HD-DVD|DVDRip|TVRip|HDTVRip|CAM|TS|DVDScr|Scr|R5)", Pattern.CASE_INSENSITIVE);
+ // Movie Video Codec Pattern
+ private Pattern movieVideoCodecPattern = Pattern.compile("(?<video_codec>XviD|DivX|DivX5|H264|X264)", Pattern.CASE_INSENSITIVE);
+ // Movie Audio Codec Pattern
+ private Pattern movieAudioCodecPattern = Pattern.compile("(?<audio_codec>AC3|DTS)", Pattern.CASE_INSENSITIVE);
+ // Movie Video Resolution Pattern
+ private Pattern movieResolutionPattern = Pattern.compile("(?<resolution>\\d+p)", Pattern.CASE_INSENSITIVE);
+ // Preferred Movie Providers
+ private List<String> movieProviders = Arrays.asList("TMDb");
+ //Configuration FIle
+ private final static String CONFIG_FILE = "org.chii2.medialibrary.core";
+ // Movie file name extract filter key from configuration file
+ private final static String MOVIE_FILE_PATTERN = "movie.file.pattern";
+ // Movie file name separator key from configuration file
+ private final static String MOVIE_NAME_SEPARATOR_PATTERN = "movie.file.name.separator";
+ // Movie file source block extract filter key from configuration file
+ private final static String MOVIE_SOURCE_PATTERN = "movie.file.source.pattern";
+ // Movie file video codec block extract filter key from configuration file
+ private final static String MOVIE_VIDEO_CODEC_PATTERN = "movie.file.video.codec.pattern";
+ // Movie file audio codec block extract filter key from configuration file
+ private final static String MOVIE_AUDIO_CODEC_PATTERN = "movie.file.audio.codec.pattern";
+ // Movie file video resolution block extract filter key from configuration file
+ private final static String MOVIE_RESOLUTION_PATTERN = "movie.file.video.resolution.pattern";
+ // Preferred Movie Provider
+ private final static String MOVIE_PROVIDER = "movie.provider";
+ // Extract Disk Number Pattern
+ private Pattern diskNumPattern = Pattern.compile("\\w*(?<number>\\d+)");
+ // Logger
+ private Logger logger;
+
+ /**
+ * Constructor
+ */
+ public MovieHandler() {
+ logger = LoggerFactory.getLogger("org.chii2.medialibrary.event");
+ }
+
+ /**
+ * Life Cycle Init
+ */
+ @SuppressWarnings("unused")
+ public void init() {
+ logger.debug("Chii2 Media Library MovieHandler init.");
+ Dictionary props = null;
+ // Read properties from ConfigAdmin Service
+ try {
+ Configuration config = configAdmin.getConfiguration(CONFIG_FILE);
+ props = config.getProperties();
+ } catch (IOException e) {
+ logger.error("MovieHandler fail to load configuration with exception: {}.", e.getMessage());
+ }
+ // Load each configuration
+ if (props == null || props.isEmpty()) {
+ logger.error("MovieHandler load configuration <{}> with error.", CONFIG_FILE);
+ } else {
+ // Load movie file name parse patterns
+ List<Pattern> namePatterns = ConfigUtils.loadPatterns(props, MOVIE_FILE_PATTERN);
+ if (namePatterns != null && !namePatterns.isEmpty()) {
+ moviePatterns = namePatterns;
+ logger.debug("MovieHandler configuration <{}> loaded.", MOVIE_FILE_PATTERN);
+ } else {
+ logger.error("MovieHandler configuration <{}> is not valid.", MOVIE_FILE_PATTERN);
+ }
+
+ // Load movie name separator pattern
+ Pattern fileSeparatorPattern = ConfigUtils.loadPattern(props, MOVIE_NAME_SEPARATOR_PATTERN);
+ if (fileSeparatorPattern != null) {
+ movieSeparatorPattern = fileSeparatorPattern;
+ logger.debug("MovieHandler configuration <{}> loaded.", MOVIE_NAME_SEPARATOR_PATTERN);
+ } else {
+ logger.error("MovieHandler configuration <{}> is not valid.", MOVIE_NAME_SEPARATOR_PATTERN);
+ }
+
+ // Load movie source pattern
+ Pattern sourcePattern = ConfigUtils.loadPattern(props, MOVIE_SOURCE_PATTERN);
+ if (sourcePattern != null) {
+ movieSourcePattern = sourcePattern;
+ logger.debug("MovieHandler configuration <{}> loaded.", MOVIE_SOURCE_PATTERN);
+ } else {
+ logger.error("MovieHandler configuration <{}> is not valid.", MOVIE_SOURCE_PATTERN);
+ }
+
+ // Load movie video codec pattern
+ Pattern videoCodecPattern = ConfigUtils.loadPattern(props, MOVIE_VIDEO_CODEC_PATTERN);
+ if (videoCodecPattern != null) {
+ movieVideoCodecPattern = videoCodecPattern;
+ logger.debug("MovieHandler configuration <{}> loaded.", MOVIE_VIDEO_CODEC_PATTERN);
+ } else {
+ logger.error("MovieHandler configuration <{}> is not valid.", MOVIE_VIDEO_CODEC_PATTERN);
+ }
+
+ // Load movie audio codec pattern
+ Pattern audioCodecPattern = ConfigUtils.loadPattern(props, MOVIE_AUDIO_CODEC_PATTERN);
+ if (audioCodecPattern != null) {
+ movieAudioCodecPattern = audioCodecPattern;
+ logger.debug("MovieHandler configuration <{}> loaded.", MOVIE_AUDIO_CODEC_PATTERN);
+ } else {
+ logger.error("MovieHandler configuration <{}> is not valid.", MOVIE_AUDIO_CODEC_PATTERN);
+ }
+
+ // Load movie video resolution pattern
+ Pattern videoResolutionPattern = ConfigUtils.loadPattern(props, MOVIE_RESOLUTION_PATTERN);
+ if (videoResolutionPattern != null) {
+ movieResolutionPattern = videoResolutionPattern;
+ logger.debug("MovieHandler configuration <{}> loaded.", MOVIE_RESOLUTION_PATTERN);
+ } else {
+ logger.error("MovieHandler configuration <{}> is not valid.", MOVIE_RESOLUTION_PATTERN);
+ }
+
+ // Load movie providers configuration
+ List<String> providers = ConfigUtils.loadConfigurations(props, MOVIE_PROVIDER);
+ if (providers != null && !providers.isEmpty()) {
+ movieProviders = providers;
+ logger.debug("MovieHandler configuration <{}> loaded.", MOVIE_PROVIDER);
+ } else {
+ logger.error("MovieHandler configuration <{}> is not valid.", MOVIE_PROVIDER);
+ }
+ }
+ }
+
+ /**
+ * Life Cycle Init
+ */
+ @SuppressWarnings("unused")
+ public void destroy() {
+ logger.debug("Chii2 Media Library MovieHandler destroy.");
+ }
+
+ @Override
+ public void handleEvent(Event event) {
+ // Movie Scan Event
+ if (FileService.MOVIE_SCAN_TOPIC.equals(event.getTopic())) {
+ // Get List of file names from event, this should be fine
+ @SuppressWarnings("unchecked")
+ List<File> files = (List<File>) event.getProperty("files");
+ logger.debug("Receive a movie scan event with {} records.", files.size());
+ doScanProcess(files);
+ }
+ // Movie Information Provided Event
+ else if (MovieInfoProviderService.MOVIE_INFO_PROVIDED_TOPIC.equals(event.getTopic())) {
+ String movieId = (String) event.getProperty(MovieInfoProviderService.MOVIE_ID_PROPERTY);
+ @SuppressWarnings("unchecked")
+ List<MovieInfo> info = (List<MovieInfo>) event.getProperty(MovieInfoProviderService.MOVIE_INFO_PROPERTY);
+ logger.debug("Receive a movie information provided event with {} information.", info.size());
+ doInfoProvidedProcess(movieId, info);
+ }
+ // Movie Information provided Failed Event
+ else if (MovieInfoProviderService.MOVIE_INFO_FAILED_TOPIC.equals(event.getTopic())) {
+ String movieId = (String) event.getProperty(MovieInfoProviderService.MOVIE_ID_PROPERTY);
+ String movieName = (String) event.getProperty(MovieInfoProviderService.MOVIE_NAME_PROPERTY);
+ String movieYear = (String) event.getProperty(MovieInfoProviderService.MOVIE_YEAR_PROPERTY);
+ @SuppressWarnings("unchecked")
+ List<String> excludedProviders = (List<String>) event.getProperty(MovieInfoProviderService.EXCLUDE_PROVIDERS_PROPERTY);
+ logger.debug("Receive a movie information failed event.");
+ // Try to re-fetch the movie information, through another provider maybe
+ notifyProviderFetchInfo(movieId, movieName, movieYear, excludedProviders);
+ }
+ // Movie Image Provided Event
+ else if (MovieInfoProviderService.MOVIE_IMAGE_PROVIDED_TOPIC.equals(event.getTopic())) {
+ String imageId = (String) event.getProperty(MovieInfoProviderService.IMAGE_ID_PROPERTY);
+ byte[] imageContent = (byte[]) event.getProperty(MovieInfoProviderService.IMAGE_CONTENT_PROPERTY);
+ logger.debug("Receive a image provided event.");
+ // Try to update image in database
+ doImageProvidedProcess(imageId, imageContent);
+ }
+ }
+
+ /**
+ * Parse provided image and save into database
+ *
+ * @param imageId Image ID
+ * @param imageContent Image Content
+ */
+ private void doImageProvidedProcess(String imageId, byte[] imageContent) {
+ // Get the image from database
+ MovieImage image = persistenceService.getMovieImageById(imageId);
+ // Add Image save back to database
+ image.setImage(imageContent);
+
+ logger.debug("Update image <{}>.", imageId);
+ // Save back to database
+ persistenceService.merge(image);
+ }
+
+ /**
+ * Parse provided movie information and save into database
+ *
+ * @param movieId Movie ID
+ * @param info Movie Information
+ */
+ private void doInfoProvidedProcess(String movieId, List<MovieInfo> info) {
+ // Get movie from database
+ Movie movie = persistenceService.getMovieById(movieId);
+ // Add information
+ for (MovieInfo movieInfo : info) {
+ movie.addInfo(movieInfo);
+ }
+
+ logger.debug("Update movie <{}> image.", movieId);
+ // Save into database
+ persistenceService.merge(movie);
+
+ // Fetch Posters and Backdrops
+ for (MovieInfo movieInfo : info) {
+ for (MovieImage image : movieInfo.getImages()) {
+ notifyProviderFetchImage(image.getId(), image.getUrl(), movieInfo.getProviderName());
+ }
+ }
+ }
+
+ /**
+ * Parse the scanned files and sync to the database
+ *
+ * @param files Scanned Files
+ */
+ private void doScanProcess(List<File> files) {
+ // List of movie files
+ List<MovieFile> movieFiles = new ArrayList<MovieFile>();
+
+ // Loop and parse the files
+ for (File file : files) {
+ // Parse file into movie file
+ MovieFile movieFile = parseFile(file);
+ // Add to list
+ movieFiles.add(movieFile);
+ }
+
+ // Synchronize the scanned movies to the database
+ synchronize(movieFiles);
+ logger.debug("Try to synchronize {} movies files.", movieFiles.size());
+ }
+
+ /**
+ * Synchronize to the database
+ *
+ * @param movieFiles Movie Files
+ */
+ private void synchronize(List<MovieFile> movieFiles) {
+ // Movie List
+ List<Movie> movies = new ArrayList<Movie>();
+
+ // Loop and create a list of movies
+ loop:
+ for (MovieFile movieFile : movieFiles) {
+ // Loop current movies seem it the file shouldIncl to any group
+ for (Movie movie : movies) {
+ if (movie.shouldIncl(movieFile)) {
+ movie.addFile(movieFile);
+ continue loop;
+ }
+ }
+
+ // If not shouldIncl to a exist movie group, create a new one
+ Movie movie = movieFactory.createMovie();
+ movie.addFile(movieFile);
+ movies.add(movie);
+ }
+
+ // Get current database movie records
+ List<? extends Movie> dbMovies = persistenceService.getAllMovies();
+
+ // Compare database and input list
+ loop:
+ for (Movie dbMovie : dbMovies) {
+ for (Movie movie : movies) {
+ if (compareMovie(movie, dbMovie)) {
+ // If they reference to the same files, fill the file id with the value from database, and make a merge
+ for (MovieFile movieFile : movie.getFiles()) {
+ movieFile.setId(dbMovie.getFileIdByName(movieFile.getAbsoluteName()));
+ logger.debug("Update movie file <{}>.", movieFile.getId());
+ // Update movie file information
+ persistenceService.merge(movieFile);
+ // If database doesn't contain movie information, try get it. The should not happen
+ if (dbMovie.getInfoCount() == 0) {
+ // Request provider to fetch movie information
+ notifyProviderFetchInfo(dbMovie.getId(), movie.getGuessedMovieName(), movie.getGuessedMovieYear(), new ArrayList<String>());
+ }
+ }
+
+ // Remove the matched ones from list
+ movies.remove(movie);
+
+ // Because match has been found, continue to loop next database movie file
+ continue loop;
+ }
+ }
+ logger.debug("Remove movie <{}>.", dbMovie.getId());
+ // If no match found, remove the movie from database
+ persistenceService.remove(dbMovie);
+ }
+ logger.debug("Save <{}> movies.", movies.size());
+ // After looping, only newly added movies left in the list, persist them
+ persistenceService.persist(movies);
+
+ // Request provider to fetch movie information
+ for (Movie movie : movies) {
+ notifyProviderFetchInfo(movie.getId(), movie.getGuessedMovieName(), movie.getGuessedMovieYear(), new ArrayList<String>());
+ }
+ }
+
+ /**
+ * Notify the provider to fetch movie information
+ *
+ * @param movieId Movie Id
+ * @param movieName Movie Name (Guessed)
+ * @param movieYear Movie Released Year (Guessed)
+ * @param excludeProviders Exclude Movie Providers (Which may already failed)
+ */
+ private void notifyProviderFetchInfo(String movieId, String movieName, String movieYear, List<String> excludeProviders) {
+ if (!providerServices.isEmpty()) {
+ // Find the provider based on configuration order and use it to fetch movie information
+ loop:
+ for (String preferredProvider : movieProviders) {
+ // If the provider on the exclude list (which usually already failed), continue to next
+ if (excludeProviders != null && excludeProviders.contains(preferredProvider)) {
+ continue;
+ }
+ // Loop the current provider see whether preferred provider is available
+ for (MovieInfoProviderService provider : providerServices) {
+ if (preferredProvider.equalsIgnoreCase(provider.getProviderName())) {
+ logger.debug("Try to get movie <{}> information with <{}> provider.", movieName, provider.getProviderName());
+ // Try to get movie information from the internet provider (this tends to work background)
+ provider.getMovieInformationByName(movieId, movieName, movieYear, excludeProviders);
+ // Once matched, stop looping
+ break loop;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Notify the provider to fetch movie image
+ *
+ * @param imageId Image ID
+ * @param url URL
+ * @param originalProvider Original Provider
+ */
+ private void notifyProviderFetchImage(String imageId, String url, String originalProvider) {
+ if (!providerServices.isEmpty()) {
+ // Loop the current provider see whether original provider is available
+ for (MovieInfoProviderService provider : providerServices) {
+ if (originalProvider.equalsIgnoreCase(provider.getProviderName())) {
+ logger.debug("Try to get movie image <{}> with <{}> provider.", imageId, provider.getProviderName());
+ // Try to get movie image from the internet provider (this tends to work background)
+ provider.getMovieImageByUrl(imageId, url);
+ // Once matched, stop
+ return;
+ }
+ }
+
+ // If original provider not presented, find the provider based on configuration order and use it to fetch image
+ loop:
+ for (String preferredProvider : movieProviders) {
+ // Loop the current provider see whether preferred provider is available
+ for (MovieInfoProviderService provider : providerServices) {
+ if (preferredProvider.equalsIgnoreCase(provider.getProviderName())) {
+ logger.debug("Try to get movie image <{}> with <{}> provider.", imageId, provider.getProviderName());
+ // Try to get movie image from the internet provider (this tends to work background)
+ provider.getMovieImageByUrl(imageId, url);
+ // Once matched, stop looping
+ break loop;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Compare whether two movie is the same (has same files)
+ *
+ * @param movie1 First movie
+ * @param movie2 Second movie
+ * @return True if two move is the same
+ */
+ private boolean compareMovie(Movie movie1, Movie movie2) {
+ // If contains different number of files, not the same
+ if (movie1.getFilesCount() != movie2.getFilesCount()) {
+ return false;
+ }
+
+ // Loop to see whether all files are matched
+ Loop:
+ for (MovieFile movieFile1 : movie1.getFiles()) {
+ for (MovieFile movieFile2 : movie2.getFiles()) {
+ // If reference to the same file, loop another file
+ if (movieFile1.getAbsoluteName().equals(movieFile2.getAbsoluteName())) {
+ continue Loop;
+ }
+ }
+
+ // If no match found, two movie are not equal
+ return false;
+ }
+
+ // If all files are matched, teo movie are equal
+ return true;
+ }
+
+ /**
+ * Parse file name and convert into MovieFile
+ *
+ * @param file File
+ * @return MovieFile
+ */
+ private MovieFile parseFile(File file) {
+ // Regexp matcher to be used
+ Matcher matcher = null;
+
+ // Create a MovieFile from factory
+ MovieFile movieFile = movieFactory.createMovieFile();
+
+ // Set MovieFile fields
+ movieFile.setAbsoluteName(file.getAbsolutePath()); // Absolute File Name(Path)
+ movieFile.setFilePath(file.getParent()); // File Path
+ movieFile.setFileName(file.getName()); // File Name
+
+ // Loop and parse file name
+ for (Pattern pattern : moviePatterns) {
+ if (matcher != null) {
+ matcher.reset();
+ }
+ // Match file name
+ matcher = pattern.matcher(file.getName());
+ if (matcher.find() && matcher.groupCount() > 0) {
+
+ // Match movie name
+ String movieName = matcher.group("name");
+ if (movieName != null && !movieName.isEmpty()) {
+ // Movie Name contains only words and spaces
+ movieFile.setMovieName(movieName.replaceAll(movieSeparatorPattern.toString(), " "));
+ }
+
+ // Match movie year
+ movieFile.setYear(matcher.group("year"));
+
+ //Match disk number
+ String disk = matcher.group("disk");
+ if (disk != null && !disk.isEmpty()) {
+ movieFile.setDiskNum(parseDiskNum(disk));
+ }
+
+ // Match release group
+ movieFile.setGroup(matcher.group("group"));
+
+ // Match file extension
+ movieFile.setFileExtension(matcher.group("ext"));
+
+ // A information block may contains other attribute
+ String movieInfo = matcher.group("info");
+ // If no movie info block matched, try to get each attribute
+ if (movieInfo == null || movieInfo.isEmpty()) {
+ movieFile.setSource(matcher.group("source")); // Source
+ movieFile.setVideoCodec(matcher.group("video_codec")); // Video Codec
+ movieFile.setAudioCodec(matcher.group("audio_codec")); // Audio Codec
+ movieFile.setResolution(matcher.group("resolution")); // Resolution
+ }
+ // If info matched, try to parse info into separate attribute
+ else {
+ // Match file source
+ matcher.reset();
+ matcher = movieSourcePattern.matcher(movieInfo);
+ if (matcher.find() && matcher.groupCount() > 0) {
+ movieFile.setSource(matcher.group("source"));
+ }
+
+ // Match movie video codec
+ matcher.reset();
+ matcher = movieVideoCodecPattern.matcher(movieInfo);
+ if (matcher.find() && matcher.groupCount() > 0) {
+ movieFile.setVideoCodec(matcher.group("video_codec"));
+ }
+
+ // Match movie audio codec
+ matcher.reset();
+ matcher = movieAudioCodecPattern.matcher(movieInfo);
+ if (matcher.find() && matcher.groupCount() > 0) {
+ movieFile.setAudioCodec(matcher.group("audio_codec"));
+ }
+
+ // Match video resolution
+ matcher.reset();
+ matcher = movieResolutionPattern.matcher(movieInfo);
+ if (matcher.find() && matcher.groupCount() > 0) {
+ movieFile.setResolution(matcher.group("resolution"));
+ }
+
+ }
+ // Once matched, Stop match loop
+ break;
+ }
+ }
+
+ return movieFile;
+ }
+
+ /**
+ * Parse disk information into disk order number
+ *
+ * @param disk Disk Information
+ * @return Disk Number
+ */
+ private int parseDiskNum(String disk) {
+ if (disk == null || disk.isEmpty()) {
+ return 1;
+ }
+
+ // Match "CD1" or "DVD2" or "1"
+ Matcher matcher = diskNumPattern.matcher(disk);
+ if (matcher.find() && matcher.groupCount() > 0) {
+ try {
+ return Integer.valueOf(matcher.group("number"));
+ } catch (NumberFormatException e) {
+ // This should not happens, since regexp is matched
+ }
+ }
+
+ // Get last char and turn it into a number
+ String num = disk.substring(disk.length() - 1);
+ if (num.equalsIgnoreCase("a")) return 1;
+ else if (num.equalsIgnoreCase("b")) return 2;
+ else if (num.equalsIgnoreCase("c")) return 3;
+ else if (num.equalsIgnoreCase("d")) return 4;
+ else if (num.equalsIgnoreCase("e")) return 5;
+ else if (num.equalsIgnoreCase("f")) return 6;
+ else if (num.equalsIgnoreCase("g")) return 7;
+ else if (num.equalsIgnoreCase("h")) return 8;
+ else if (num.equalsIgnoreCase("i")) return 9;
+ else if (num.equalsIgnoreCase("j")) return 10;
+ else if (num.equalsIgnoreCase("k")) return 11;
+ else if (num.equalsIgnoreCase("l")) return 12;
+ else if (num.equalsIgnoreCase("m")) return 13;
+ else if (num.equalsIgnoreCase("n")) return 14;
+ else if (num.equalsIgnoreCase("o")) return 15;
+ else if (num.equalsIgnoreCase("p")) return 16;
+ else if (num.equalsIgnoreCase("q")) return 17;
+ else if (num.equalsIgnoreCase("r")) return 18;
+ else if (num.equalsIgnoreCase("s")) return 19;
+ else if (num.equalsIgnoreCase("t")) return 20;
+ else if (num.equalsIgnoreCase("u")) return 21;
+ else if (num.equalsIgnoreCase("v")) return 22;
+ else if (num.equalsIgnoreCase("w")) return 23;
+ else if (num.equalsIgnoreCase("x")) return 24;
+ else if (num.equalsIgnoreCase("y")) return 25;
+ else if (num.equalsIgnoreCase("z")) return 26;
+
+ // None matched, just return 1
+ return 1;
+ }
+
+ /**
+ * Inject Config Admin
+ *
+ * @param configAdmin Config Admin
+ */
+ @SuppressWarnings("unused")
+ public void setConfigAdmin(ConfigurationAdmin configAdmin) {
+ this.configAdmin = configAdmin;
+ }
+
+ /**
+ * Inject EventAdmin service
+ *
+ * @param eventAdmin EventAdmin service
+ */
+ @SuppressWarnings("unused")
+ public void setEventAdmin(EventAdmin eventAdmin) {
+ this.eventAdmin = eventAdmin;
+ }
+
+ /**
+ * Inject Persistence Service
+ *
+ * @param persistenceService Persistence Service
+ */
+ @SuppressWarnings("unused")
+ public void setPersistenceService(PersistenceService persistenceService) {
+ this.persistenceService = persistenceService;
+ }
+
+ /**
+ * Inject Movie Factory
+ *
+ * @param movieFactory Movie Factory
+ */
+ @SuppressWarnings("unused")
+ public void setMovieFactory(MovieFactory movieFactory) {
+ this.movieFactory = movieFactory;
+ }
+
+ /**
+ * Inject Movie Information Provider Services
+ *
+ * @param providerServices Movie Information Provider Services
+ */
+ @SuppressWarnings("unused")
+ public void setProviderServices(List<MovieInfoProviderService> providerServices) {
+ this.providerServices = providerServices;
+ }
+}
+
View
68 medialibrary.core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <!-- OSGi Configuration Admin Service -->
+ <reference id="configAdminService"
+ interface="org.osgi.service.cm.ConfigurationAdmin"/>
+
+ <!-- OSGi Event Admin Service -->
+ <reference id="eventAdminService"
+ interface="org.osgi.service.event.EventAdmin"/>
+
+ <!-- Chii2 Media Library Persistence Service -->
+ <reference id="persistenceManager"
+ interface="org.chii2.medialibrary.api.persistence.PersistenceService"/>
+
+ <!-- Chii2 Media Library Movie Factory -->
+ <reference id="movieFactoryManager"
+ interface="org.chii2.medialibrary.api.persistence.factory.MovieFactory"/>
+
+ <!-- Chii2 Media Library File Service -->
+ <reference id="fileManager"
+ interface="org.chii2.medialibrary.api.file.FileService"/>
+
+ <!-- Chii2 Media Library Movie Information Provider Service -->
+ <reference-list id="movieProviderManager"
+ interface="org.chii2.medialibrary.api.provider.MovieInfoProviderService"/>
+
+ <!-- Chii2 Media Library Core Bean -->
+ <bean id="medialibraryService" class="org.chii2.medialibrary.MediaLibraryServiceImpl"
+ init-method="init"
+ destroy-method="destroy">
+ <property name="persistenceService" ref="persistenceManager"/>
+ <property name="fileService" ref="fileManager"/>
+ </bean>
+
+ <!-- Chii2 Media Library Movie Event Handler Bean -->
+ <bean id="movieHandler" class="org.chii2.medialibrary.event.MovieHandler"
+ init-method="init"
+ destroy-method="destroy">
+ <property name="configAdmin" ref="configAdminService"/>
+ <property name="eventAdmin" ref="eventAdminService"/>
+ <property name="persistenceService" ref="persistenceManager"/>
+ <property name="movieFactory" ref="movieFactoryManager"/>
+ <property name="providerServices" ref="movieProviderManager"/>
+ </bean>
+
+ <!-- Chii2 Media Library Core Service -->
+ <service ref="medialibraryService" interface="org.chii2.medialibrary.api.core.MediaLibraryService">
+ </service>
+
+ <!-- Chii2 Media Library Movie Event Handler Service -->
+ <service ref="movieHandler"
+ interface="org.osgi.service.event.EventHandler">
+ <service-properties>
+ <!-- Register Event Topics -->
+ <entry key="event.topics">
+ <list>
+ <value>org/chii2/medialibrary/file/movie/SCAN</value>
+ <value>org/chii2/medialibrary/provider/movie/INFO_PROVIDED</value>
+ <value>org/chii2/medialibrary/provider/movie/INFO_FAILED</value>
+ <value>org/chii2/medialibrary/provider/movie/IMAGE_PROVIDED</value>
+ </list>
+ </entry>
+ </service-properties>
+ </service>
+
+</blueprint>
View
50 medialibrary.datasource/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>chii2</artifactId>
+ <groupId>org.chii2</groupId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>chii2.medialibrary.datasource</artifactId>
+ <packaging>bundle</packaging>
+
+ <name>Chii2 Media Library DataSource</name>
+ <url>http://www.chii2.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.transaction</groupId>
+ <artifactId>org.apache.aries.transaction.blueprint</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.components</groupId>
+ <artifactId>geronimo-transaction</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
View
32 medialibrary.datasource/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ <!-- JDBC JTA Data Source Bean -->
+ <bean id="derbyXADataSource" class="org.apache.derby.jdbc.EmbeddedXADataSource">
+ <property name="databaseName" value="data/Chii2DB"/>
+ <property name="createDatabase" value="create"/>
+ </bean>
+
+ <!-- JDBC JTA Data Source Service -->
+ <service id="xaDataSource" ref="derbyXADataSource" interface="javax.sql.XADataSource">
+ <service-properties>
+ <entry key="osgi.jndi.service.name" value="jdbc/chii2db"/>
+ </service-properties>
+ </service>
+
+ <!-- JDBC Data Source Bean -->
+ <bean id="derbyDataSource" class="org.apache.derby.jdbc.EmbeddedDataSource">
+ <property name="databaseName" value="data/Chii2DB"/>
+ <property name="createDatabase" value="create"/>
+ </bean>
+
+ <!-- JDBC Data Source Service -->
+ <service ref="derbyDataSource" interface="javax.sql.DataSource">
+ <service-properties>
+ <entry key="osgi.jndi.service.name" value="jdbc/chii2dbnojta"/>
+ </service-properties>
+ </service>
+
+</blueprint>
View
67 medialibrary.file/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>chii2</artifactId>
+ <groupId>org.chii2</groupId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>chii2.medialibrary.file</artifactId>
+ <packaging>bundle</packaging>
+
+ <name>Chii2 Media Library File</name>
+ <url>http://www.chii2.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.chii2</groupId>
+ <artifactId>chii2.medialibrary.api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.chii2</groupId>
+ <artifactId>chii2.utility</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.eventadmin</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>org.chii2.medialibrary.file</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
View
48 medialibrary.file/src/main/java/org/chii2/medialibrary/file/FileExtensionFilter.java
@@ -0,0 +1,48 @@
+package org.chii2.medialibrary.file;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.List;
+
+/**
+ * FileExtensionFilter is used to filer the file name with FileScanner
+ */
+public class FileExtensionFilter implements FileFilter {
+
+ // Acceptable File Extensions
+ private List<String> acceptableExtensions;
+ // Logger
+ private Logger logger;
+
+ public FileExtensionFilter(List<String> acceptableExtensions) {
+ this.acceptableExtensions = acceptableExtensions;
+ logger = LoggerFactory.getLogger("org.chii2.medialibrary.file");
+ }
+
+ @Override
+ public boolean accept(File file) {
+ // If is directory, accept to go into
+ if (file.isDirectory()) {
+ return true;
+ }
+ // Empty file
+ if (file.getName().isEmpty()) {
+ logger.debug("File is rejected with empty name.");
+ return false;
+ }
+ // Test file extension
+ for (String ext : acceptableExtensions) {
+ if (ext != null && !ext.isEmpty() && file.getName().endsWith(ext)) {
+ logger.debug("File <{}> is accepted.", file.getName());
+ return true;
+ }
+ }
+ // Should not reach, in case just reject
+ logger.debug("File <{}> is rejected.", file.getName());
+ return false;
+ }
+
+}
View
92 medialibrary.file/src/main/java/org/chii2/medialibrary/file/FileScanner.java
@@ -0,0 +1,92 @@
+package org.chii2.medialibrary.file;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+/**
+ * FileScanner is used to scan directories for a give type of file
+ */
+public class FileScanner implements Runnable {
+
+ // Directories to be scanned
+ private List<File> directories;
+ // File Name Filter
+ private FileFilter filter;
+ // EventAdmin
+ private EventAdmin eventAdmin;
+ // EventAdmin Topic
+ private String topic;
+ // Found Files
+ List<File> files = new ArrayList<File>();
+ // Logger
+ private Logger logger;
+
+ public FileScanner(List<File> directories, FileFilter filter, EventAdmin eventAdmin, String topic) {
+ this.directories = directories;
+ this.filter = filter;
+ this.eventAdmin = eventAdmin;
+ this.topic = topic;
+ logger = LoggerFactory.getLogger("org.chii2.medialibrary.file");
+ }
+
+ @Override
+ public void run() {
+ logger.debug("File Scanner start.");
+ if (directories != null && !directories.isEmpty()) {
+ try {
+ for (File directory : directories) {
+ if (directory != null && directory.exists() && directory.isDirectory()) {
+ scanFiles(directory, filter);
+ }
+ }
+ } catch (SecurityException e) {
+ logger.warn("File access failed with exception: {}", e.getMessage());
+ }
+ if (files != null && !files.isEmpty()) {
+ sendEvent(files, topic);
+ }
+ }
+ logger.debug("File Scanner stop.");
+ }
+
+ /**
+ * Scan a directory recursively
+ *
+ * @param directory Directory to be scanned
+ * @param filter File Name Filter
+ */
+ private void scanFiles(File directory, FileFilter filter) {
+ for (File file : directory.listFiles(filter)) {
+ if (file.isDirectory()) {
+ scanFiles(file, filter);
+ } else {
+ files.add(file);
+ logger.info("Found a new file: {}.", file.getName());
+ }
+ }
+ }
+
+ /**
+ * Send a scan event asynchronously
+ *
+ * @param files Files discovered
+ * @param topic Event topic
+ */
+ private void sendEvent(List<File> files, String topic) {
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put("files", files);
+ Event event = new Event(topic, properties);
+ logger.debug("Send a movie scan event with {} records.", files.size());
+ eventAdmin.postEvent(event);
+ }
+
+}
View
188 medialibrary.file/src/main/java/org/chii2/medialibrary/file/FileServiceImpl.java
@@ -0,0 +1,188 @@
+package org.chii2.medialibrary.file;
+
+import org.apache.commons.lang.StringUtils;
+import org.chii2.medialibrary.api.file.FileService;
+import org.chii2.util.ConfigUtils;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.List;
+
+/**
+ * FileService Implement provide watcher and scanner functionality
+ */
+public class FileServiceImpl implements FileService {
+
+ // Injected ConfigAdmin Service
+ private ConfigurationAdmin configAdmin;
+ // Injected EventAdmin Service
+ private EventAdmin eventAdmin;
+ //Configuration FIle
+ private final static String CONFIG_FILE = "org.chii2.medialibrary.file";
+ // Movie Directory Configuration Key
+ private static final String MOVIE_DIRECTORY = "movie.directory";
+ // Video File Extension Configuration Key
+ private static final String VIDEO_EXTENSION = "video.extension";
+ // Movie directories from configuration
+ private List<String> movieDirectories = Arrays.asList("/Share/Movie");
+ // Movie file extension filter