diff --git a/Makefile.am b/Makefile.am
index 588149ae..99025d4e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,3 +3,23 @@ AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip
SUBDIRS = test src
+lms_docrootdir=$(pkgdatadir)/docroot
+lms_approotdir=$(pkgdatadir)/approot
+
+lms_cssdir=$(lms_docrootdir)/css
+lms_imagesdir=$(lms_docrootdir)/images
+
+lms_css_DATA = \
+ docroot/css/lms.css
+
+lms_images_DATA = \
+ docroot/images/unknown-cover.jpg
+
+lms_approot_DATA = \
+ approot/templates.xml
+
+install-data-hook:
+ ln -s $(datadir)/Wt/resources $(lms_docrootdir)/resources || echo "Skipped symlink creation"
+
+uninstall-local:
+ cd $(lms_docrootdir) && rm -f -r $(lms_docrootdir)/resources
diff --git a/README.md b/README.md
index 301cb990..2ecaa872 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,6 @@ It allows you to access your music and your videos using an https web interface.
- Winamp-like interface, suited for large databases
- Audio/Video transcode for maximum interoperability and low bandwith requirements
- User management
- - LMS API available in Protocol Buffers (see src/lms-api/proto/messages.proto)
Please note LMS is still under development and will gain more features in the future.
@@ -17,63 +16,51 @@ Please note some media files may require significant CPU usage to be transcoded.
## Dependencies
### Debian or Ubuntu packages
```sh
-$ apt-get install g++ autoconf automake libboost-dev libboost-locale-dev libboost-iostreams-dev libboost-log-dev libavcodec-dev libwtdbosqlite-dev libwthttp-dev libwtdbo-dev libwt-dev libconfig++-dev libjpeg8-dev libavcodec-dev libavformat-dev libavutil-dvegi libav-tools
+$ apt-get install g++ autoconf automake libboost-dev libboost-locale-dev libboost-iostreams-dev libboost-log-dev libavcodec-dev libwtdbosqlite-dev libwthttp-dev libwtdbo-dev libwt-dev libmagick++-dev libavcodec-dev libavformat-dev libavutil
```
-If you want to enable the LMS API, you need these additional packages:
-
-```sh
-$ apt-get install libprotobuf-dev libprotobuf-dev protobuf-compiler
-```
-
-Warning: your distrib may provide an outdated wt library. Using the latest Wt (>= 3.3.3) is highly recommended (see http://www.webtoolkit.eu/wt)
-
## Build
```sh
$ autoreconf -vfi
$ mkdir build
$ cd build
-$ ../configure
+$ ../configure --prefix=/usr
```
-
configure will complain if a mandatory library is missing.
-The configure script allows you to disable the LMS API support, see 'configure --help' for more information.
```sh
-$ make
+$ make -j 4
```
-## Setting up SSL materials
-This is required by the SSL server and the web server.
+## Install
+```sh
+$ make install
+```
+This command requires root privileges
+## Running
+```sh
+$ /usr/bin/lms --docroot='/usr/share/lms/docroot/;/resources,/css,/images' --approot=/usr/share/lms/approot --http-address 0.0.0.0 --http-port 5081
+```
+It is highly recommended to run LMS as a non root user.
+The exectuable needs write accesses to the /var/lms/ directory.
+
+## Setting up SSL materials (optional)
Here is just a self signed certificate example, you could do use a CA if you want.
Generate a dh file:
```sh
$ openssl dhparam -out dh2048.pem 2048
```
-
Generate a self signed certificate:
```sh
$ openssl req -x509 -out cert.pem -keyout privkey.pem -newkey rsa:4096
```
-## Running
-
-In the build directory:
```sh
-$ ./src/lms lms.conf
+$ /usr/bin/lms --docroot='/usr/share/lms/docroot/;/resources,/css,/images' --approot=/usr/share/lms/approot --https-address 0.0.0.0 --https-port 5081 --ssl-certificate cert.pem --ssl-private-key privkey.pem --ssl-tmp-dh dh2048.pem
```
-
-Create the lms.conf file using the etc/lms.sample.conf
- - "ui.resources.approot" has to refer to the ui/approot/ directory.
- - "ui.resources.docroot" has to refer to the ui/docroot/ directory
-You must also link Wt's docroot (usually located in /usr/share/Wt) into that directory. Example:
-```sh
-ln -s /var/lms/docroot/resources /usr/share/Wt/resources
-```
-
Depending on your SSL parameters, you may be asked for the PEM passphrase to unlock the private key.
## Credits
@@ -81,5 +68,4 @@ Depending on your SSL parameters, you may be asked for the PEM passphrase to unl
- Wt (http://www.webtoolkit.eu/)
- bootstrap3 (http://getbootstrap.com/)
- libav project (https://www.libav.org/).
-- Protocol Buffers (https://github.com/google/protobuf/)
73,1 Bot
diff --git a/TODO b/TODO
index 01b7e987..4994d6a7 100644
--- a/TODO
+++ b/TODO
@@ -3,8 +3,6 @@
- Make the feature
[Cover]
-- Scaling: find something more "reliable" than GIL and its custom extensions (adobe work, io_new)?
-- Handle several file formats (not only jpg), use libmagic?
- Handle preferred cover file names
- Implement a cache and a grabber from some web service (mandatory for artists)
@@ -25,18 +23,12 @@
[Users]
- Handle login lifetime?
-- Limit multi login from UI and remote interfaces (limit per interface is acceptable)
-
-[ServiceManager]
-- Rework the whole start/stop/try/cach/thread/interrupts things
-- Use our own WIOService
+- Use the WServer::post method to kick users already logged in?
+- Limit multi login from UI and API interfaces (limit per interface is acceptable)
[Services]
- consider adding support for external web servers (new FCGI service?)
-[Transcode]
-- some early end of playback spotted on files. Maybe this is because the stderr of the forked process is not properly closed?
-
[UI]
- handle internationalization
[Settings]
@@ -74,12 +66,8 @@
- Make a dedicated audio layout in mobile environment (keep the same layout for videos?)
- Handle internal path
-[Lms API]
-- Implement partial text search options in the GetXXX messages
-- Make it REST ?
-
[REST API]
-- Make another dedicated REST API. Maybe use the SubSonic API or Ampache API?
+- Make a dedicated REST API. Maybe use the SubSonic API or Ampache API?
[Logs]
-- Capture transcoder log output to get more information on errors
+- Capture transcoder log output to get more information on errors?
diff --git a/src/ui/approot/templates.xml b/approot/templates.xml
similarity index 100%
rename from src/ui/approot/templates.xml
rename to approot/templates.xml
diff --git a/conf/lms.conf.sample b/conf/lms.conf.sample
deleted file mode 100644
index 01ffec79..00000000
--- a/conf/lms.conf.sample
+++ /dev/null
@@ -1,63 +0,0 @@
-
-main = {
-
- logger = {
- level = 7; # level common for all loggers
- file = {
- enable = true;
- path = "/var/lms/lms.log"; # comment to disable file logging
- }
- console = {
- enable = true;
- }
- }
-
- database = {
- path = "/var/lms/lms.db";
-
- audio_extensions = "mp3 ogg oga aac m4a flac wav wma aif aiff ape mpc shn";
- video_extensions = "flv avi mpg mpeg mp4 m4v mkv mov wmv ogv divx m2ts";
- }
-
- cover = {
- file_extensions = "jpg jpeg";
- file_max_size = 5000000;
- file_preferred_names = "cover front";
- }
-}
-
-
-ui = {
- resources = {
- docroot = "/var/lms/docroot"
- approot = "/var/lms/approot"
- }
-
- listen-endpoint = {
- port = 5081;
- addr = "0.0.0.0";
- }
-
- ssl-crypto = {
- cert = "/var/lms/certs/certUI.pem";
- key = "/var/lms/private/privkeyUI.pem";
- dh = "/var/lms/dh/dh2048.pem";
- }
-
-}
-
-remote = {
- nb-threads = 1;
-
- listen-endpoint = {
- port = 5080;
- addr = "0.0.0.0";
- }
-
- ssl-crypto = {
- cert = "/var/lms/certs/certRemote.pem";
- key = "/var/lms/private/privkeyRemote.pem";
- dh = "/var/lms/dh/dh2048.pem";
- }
-}
-
diff --git a/configure.ac b/configure.ac
index e7408b53..c7af1f14 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,56 +8,26 @@ AC_LANG_CPLUSPLUS
# Checks for programs
AC_PROG_CXX
+AC_ARG_ENABLE([video], AS_HELP_STRING([--enable-video],
+ [Enable Video support. Default to no.])],
+ [enable_video="$enableval"],
+ [enable_video="no"])
-AC_ARG_ENABLE(lmsapi, AS_HELP_STRING([--enable-lmsapi],
- [Build with the lmsapi protocol support. Defaults to yes.])],
- [enable_lmsapi="$enableval"],
- [enable_lmsapi="yes"])
+AM_CONDITIONAL([VIDEO], [test x$enable_video = xyes])
+AS_IF([test x$enable_video = xyes], [AC_DEFINE(HAVE_VIDEO, [1], [Enable Video support])])
-# ProtoBuf compiler.
-# First, specify with --with-protoc=/path/of/protoc.
-# Or, specify with env variable PROTOC.
-# If neither of the above, find it in the path.
-AS_IF([test "$enable_lmsapi" = "yes"],
- [AC_ARG_WITH([protoc],
- [AS_HELP_STRING([--with-protoc=/path/of/protoc],
- [Location of the protocol buffers compiler protoc. Defaults to looking on path.])],
- [PROTOC="$withval"],
- [ AS_IF([test "x${PROTOC}" == "x"],
- [AC_PATH_PROG([PROTOC], [protoc], [no])])]
- )
- ]
- [ AS_IF([test "${PROTOC}" == "no"], [AC_MSG_ERROR([ProtoBuf compiler "protoc" not found.])]) ]
- [AC_CHECK_LIB( [protobuf],
- [main],
- ,
- [AC_MSG_ERROR([libprotobuf not found!])])]
- [lmsapi=true]
- ,
- [lmsapi=false])
+PKG_CHECK_MODULES(IMAGEMAGICKXX, "ImageMagick++", [ HAVE_IMAGEMAGICKXX=yes ], [ ])
+if test -n "$HAVE_IMAGEMAGICKXX"; then
+ MAGICKXX_CFLAGS="$IMAGEMAGICKXX_CFLAGS"
+ MAGICKXX_LIBS="$IMAGEMAGICKXX_LIBS"
+fi
+AC_SUBST(MAGICKXX_CFLAGS)
+AC_SUBST(MAGICKXX_LIBS)
-AM_CONDITIONAL([LMSAPI], [test x$lmsapi = xtrue])
-AS_IF([test x$lmsapi = xtrue], [AC_DEFINE(HAVE_LMSAPI, [1], [Enable LMS API support])])
-
-AC_CHECK_HEADERS([Wt/WApplication jpeglib.h],
+AC_CHECK_HEADERS([Wt/WApplication],
[],
[AC_MSG_ERROR([Header not found or unusable !])])
-AC_CHECK_LIB([config++],
- [main],
- ,
- [AC_MSG_ERROR([config++ not found!])])
-
-AC_CHECK_LIB([jpeg],
- [jpeg_destroy],
- ,
- [AC_MSG_ERROR([libpthread not found!])])
-
-AC_CHECK_LIB([pthread],
- [pthread_create],
- ,
- [AC_MSG_ERROR([libpthread not found!])])
-
AC_CHECK_LIB([avutil],
[av_free],
,
@@ -73,16 +43,6 @@ AC_CHECK_LIB([avformat],
,
[AC_MSG_ERROR([libavformat not found!])])
-AC_CHECK_LIB([ssl],
- [SSL_CTX_new],
- ,
- [AC_MSG_ERROR([libssl not found!])])
-
-AC_CHECK_LIB([crypto],
- [ASN1_STRING_to_UTF8],
- ,
- [AC_MSG_ERROR([libcrypto not found!])])
-
AC_CHECK_LIB([boost_system],
[main],
,
@@ -118,16 +78,6 @@ AC_CHECK_LIB( [boost_iostreams],
,
[AC_MSG_ERROR([libboost_iostreams not found!])])
-AC_CHECK_LIB( [boost_log],
- [main],
- ,
- [AC_MSG_ERROR([libboost_log not found!])])
-
-AC_CHECK_LIB( [boost_log_setup],
- [main],
- ,
- [AC_MSG_ERROR([libboost_log_setup not found!])])
-
# TODO -> PARAMETRIZE THIS
AC_CHECK_LIB([wthttp],
[main],
diff --git a/src/ui/docroot/css/lms.css b/docroot/css/lms.css
similarity index 100%
rename from src/ui/docroot/css/lms.css
rename to docroot/css/lms.css
diff --git a/src/ui/docroot/images/unknown-cover.jpg b/docroot/images/unknown-cover.jpg
similarity index 100%
rename from src/ui/docroot/images/unknown-cover.jpg
rename to docroot/images/unknown-cover.jpg
diff --git a/lms-api/proto/auth.proto b/lms-api/proto/auth.proto
deleted file mode 100644
index 1ad02a48..00000000
--- a/lms-api/proto/auth.proto
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2013 Emeric Poupon
- *
- * This file is part of LMS.
- *
- * LMS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LMS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with LMS. If not, see .
- */
-
-package LmsAPI;
-
-message AuthRequest
-{
- message Password
- {
- required string user_login = 1;
- required string user_password = 2;
- }
-
- enum Type
- {
- TypePassword = 1;
- }
-
- required Type type = 1;
-
- optional Password password = 2;
-}
-
-message AuthResponse
-{
-
- message PasswordResult
- {
- enum Type
- {
- TypePasswordInvalid = 1;
- TypeLoginThrottling = 2; // The attempt was not processed because of throttling
- TypePasswordValid = 3;
- }
- required Type type = 1;
-
- optional uint32 delay = 2; // in seconds, in case of PasswordInvalid/LoginThrottling
- }
-
- enum Type
- {
- TypePasswordResult = 1;
- }
-
- required Type type = 1;
-
- optional PasswordResult password_result = 2;
-}
-
diff --git a/lms-api/proto/collection.proto b/lms-api/proto/collection.proto
deleted file mode 100644
index 8666a98b..00000000
--- a/lms-api/proto/collection.proto
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2013 Emeric Poupon
- *
- * This file is part of LMS.
- *
- * LMS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LMS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with LMS. If not, see .
- */
-
-package LmsAPI;
-
-message AudioCollectionRequest
-{
-
- message SearchFilter
- {
- repeated uint64 artist_id = 1; // has one of these artists
- repeated uint64 genre_id = 2; // has one of these genres
- repeated uint64 release_id = 3; // hase one of these releases
- repeated uint64 track_id = 4; // has one of theses tracks
- }
-
- message BatchParameter
- {
- required uint32 offset = 1; // First element requested
- required uint32 size = 2; // Number of elements requested. Server may not honor this size if too big
- }
-
- message GetGenreList
- {
- required BatchParameter batch_parameter = 1;
- optional SearchFilter search_filter = 2;
- }
-
- message GetArtistList
- {
- required BatchParameter batch_parameter = 1;
- optional SearchFilter search_filter = 2;
- }
-
- message GetReleaseList
- {
- required BatchParameter batch_parameter = 1;
- optional SearchFilter search_filter = 2;
- }
-
- message GetTrackList
- {
- required BatchParameter batch_parameter = 1;
- optional SearchFilter search_filter = 2;
- }
-
- message GetCoverArt
- {
- enum Type
- {
- TypeGetCoverArtRelease = 1;
- TypeGetCoverArtTrack = 2;
- }
-
- required Type type = 1;
-
- optional uint64 release_id = 2; // Release that owns the cover art
- optional uint64 track_id = 3; // Track that owns the cover art
-
- required uint32 size = 4; // Scale image to size*size pixels. Set 0 to get the biggest image
- }
-
- enum Type
- {
- TypeGetRevision = 1;
- TypeGetGenreList = 2;
- TypeGetArtistList = 3;
- TypeGetReleaseList = 4;
- TypeGetTrackList = 5;
- TypeGetCoverArt = 6;
- }
-
- required Type type = 1;
-
- optional GetGenreList get_genres = 3;
- optional GetArtistList get_artists = 4;
- optional GetReleaseList get_releases = 5;
- optional GetTrackList get_tracks = 6;
- optional GetCoverArt get_cover_art = 7;
-}
-
-
-message AudioCollectionResponse
-{
-
- message Revision
- {
- required string rev = 1; // Unique identifier of the database revision
- }
-
- message GenreList
- {
- repeated Genre genres = 1;
- }
-
- message ArtistList
- {
- repeated Artist artists = 1;
- }
-
- message ReleaseList
- {
- repeated Release releases = 1;
- }
-
- message TrackList
- {
- repeated Track tracks = 1;
- }
-
- message CoverArt
- {
- optional string mime_type = 1;
- required bytes data = 2;
- }
-
- message Genre
- {
- required uint64 id = 1;
- optional string mbid = 2;
- required string name = 3;
- }
-
- message Artist
- {
- required uint64 id = 1;
- optional string mbid = 2;
- required string name = 3;
- }
-
- message Release
- {
- required uint64 id = 1;
- optional string mbid = 2;
- required string name = 3;
- }
-
- message Track
- {
- required uint64 id = 1; // Track id
- optional string mbid = 2;
-
- required uint64 artist_id = 3;
- required uint64 release_id = 4;
- repeated uint64 genre_id = 5;
-
- optional string artist_mbid = 6;
- optional string release_mbid = 7;
- optional uint32 disc_number = 8;
- optional uint32 track_number = 9;
- required string name = 10;
- required uint32 duration_secs = 11;
- optional string release_date = 12;
- optional string original_release_date = 13;
- }
-
- enum Type {
- TypeRevision = 1;
- TypeGenreList = 2;
- TypeArtistList = 3;
- TypeReleaseList = 4;
- TypeTrackList = 5;
- TypeCoverArt = 6;
- }
-
-
- required Type type = 1;
-
- optional Revision revision = 2;
- optional GenreList genre_list = 3;
- optional ArtistList artist_list = 4;
- optional ReleaseList release_list = 5;
- optional TrackList track_list = 6;
- repeated CoverArt cover_art = 7;
-}
-
-
-
-
diff --git a/lms-api/proto/media.proto b/lms-api/proto/media.proto
deleted file mode 100644
index 20af5d02..00000000
--- a/lms-api/proto/media.proto
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2013 Emeric Poupon
- *
- * This file is part of LMS.
- *
- * LMS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LMS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with LMS. If not, see .
- */
-
-package LmsAPI;
-
-message MediaRequest
-{
-
- message Prepare
- {
-
- enum AudioCodecType
- {
- AudioCodecTypeOGA = 1;
- }
- enum AudioBitrate {
- AudioBitrate_32_kbps = 1;
- AudioBitrate_64_kbps = 2;
- AudioBitrate_96_kbps = 3;
- AudioBitrate_128_kbps = 4;
- AudioBitrate_192_kbps = 5;
- AudioBitrate_256_kbps = 6;
- }
-
- enum VideoCodecType
- {
- VideoCodecTypeOGV = 1;
- }
- enum VideoBitrate {
- VideoBitrate_512_kbps = 1;
- }
-
- message Audio
- {
- required int64 track_id = 1; // Id if the media
- required AudioCodecType codec_type = 2;
- required AudioBitrate bitrate = 3;
- optional uint32 stream_idx = 4;
- optional uint32 offset_secs = 5;
- }
-
- message Video
- {
- required int64 video_id = 1; // Id if the media
- required VideoCodecType codec_type = 2;
- required AudioBitrate audio_bitrate = 3;
- required VideoBitrate video_bitrate = 4;
- optional uint32 offset_secs = 5;
- optional uint32 audio_stream_idx = 6;
- optional uint32 video_stream_idx = 7;
- optional uint32 subtitle_stream_idx = 8;
- }
-
- enum Type {
- AudioRequest = 1;
- VideoRequest = 2;
- }
-
- required Type type = 1;
-
- optional Audio audio = 2;
- optional Video video = 3;
- }
-
- message GetPart
- {
- required uint32 handle = 1; // handle that uniquely identify the media. Get using the Prepare request
- required uint32 requested_data_size = 2; // Amount of data requested. May receive more or less. May receive 0 byte if complete
- }
-
- message Terminate
- {
- required uint32 handle = 1;
- }
-
- enum Type
- {
- TypeMediaPrepare = 1;
- TypeMediaGetPart = 2;
- TypeMediaTerminate = 3;
- }
-
- required Type type = 1;
-
- optional Prepare prepare = 2;
- optional GetPart get_part = 3;
- optional Terminate terminate = 4;
-
-} // MediaRequest
-
-message MediaResponse
-{
-
- message PrepareResult
- {
- optional uint32 handle = 1; // handle iif prepare request was ok
- }
-
- message PartResult
- {
- optional bytes data = 2; // 0 bytes when the media is over, nothing when the request is ill formed
- }
-
- message TerminateResult
- {
- }
-
- enum Type
- {
- TypePrepareResult = 1;
- TypePartResult = 2;
- TypeTerminateResult = 3;
- }
-
- required Type type = 1;
-
- optional PrepareResult prepare_result = 2;
- optional PartResult part_result = 3;
- optional TerminateResult terminate_result = 4;
-}
-
diff --git a/lms-api/proto/messages.proto b/lms-api/proto/messages.proto
deleted file mode 100644
index a6eb280b..00000000
--- a/lms-api/proto/messages.proto
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2013 Emeric Poupon
- *
- * This file is part of LMS.
- *
- * LMS is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LMS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with LMS. If not, see .
- */
-
-import "auth.proto";
-import "collection.proto";
-import "media.proto";
-
-package LmsAPI;
-
-// Every request sent by the client must be a ClientMessage
-// The server will answer using a ServerMessage
-//
-// The client must authenticate first before querying data
-// If an expected message is received, the connection is dropped by the server
-//
-// A header is to be added before the serialized protobuf message in order to keep
-// track of where one message ends and the next begins.
-// Format:
-// MAGIC (4 bytes, 0xDE, 0xAD, 0xBE, 0xEF)- SIZE (4 bytes, big endian encoded) - serialized proto message
-message ClientMessage
-{
- enum Type
- {
- AuthRequest = 1;
- AudioCollectionRequest = 2;
- MediaRequest = 3;
- }
-
- required Type type = 1;
-
- optional AuthRequest auth_request = 2;
- optional AudioCollectionRequest audio_collection_request = 3;
- optional MediaRequest media_request = 4;
-}
-
-
-message ServerMessage
-{
- enum Type
- {
- AuthResponse = 1;
- AudioCollectionResponse = 2;
- MediaResponse = 3;
- }
-
- required Type type = 1;
-
- optional AuthResponse auth_response = 2;
- optional AudioCollectionResponse audio_collection_response = 3;
- optional MediaResponse media_response = 4;
-}
-
-
diff --git a/src/Makefile.am b/src/Makefile.am
index e60d4e1c..ce6a0c12 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,14 +2,8 @@ bin_PROGRAMS = lms
lms_SOURCES = \
$(srcdir)/main/main.cpp \
- $(srcdir)/av/CodecContext.cpp \
- $(srcdir)/av/Common.cpp \
- $(srcdir)/av/Dictionary.cpp \
- $(srcdir)/av/FormatContext.cpp \
- $(srcdir)/av/InputFormatContext.cpp \
- $(srcdir)/av/Stream.cpp \
- $(srcdir)/config/ConfigReader.cpp \
- $(srcdir)/cover/CoverArt.cpp \
+ $(srcdir)/av/AvInfo.cpp \
+ $(srcdir)/av/AvTranscoder.cpp \
$(srcdir)/cover/CoverArtGrabber.cpp \
$(srcdir)/database/Artist.cpp \
$(srcdir)/database/DatabaseHandler.cpp \
@@ -23,16 +17,12 @@ lms_SOURCES = \
$(srcdir)/database/Video.cpp \
$(srcdir)/database-updater/DatabaseUpdater.cpp \
$(srcdir)/database-updater/Checksum.cpp \
+ $(srcdir)/image/Image.cpp \
$(srcdir)/logger/Logger.cpp \
$(srcdir)/metadata/AvFormat.cpp \
$(srcdir)/metadata/Utils.cpp \
$(srcdir)/service/ServiceManager.cpp \
$(srcdir)/service/DatabaseUpdateService.cpp \
- $(srcdir)/service/UserInterfaceService.cpp \
- $(srcdir)/transcode/AvConvTranscoder.cpp \
- $(srcdir)/transcode/Format.cpp \
- $(srcdir)/transcode/Parameters.cpp \
- $(srcdir)/transcode/InputMediaFile.cpp \
$(srcdir)/ui/LmsApplication.cpp \
$(srcdir)/ui/auth/LmsAuth.cpp \
$(srcdir)/ui/audio/desktop/DesktopAudio.cpp \
@@ -51,10 +41,6 @@ lms_SOURCES = \
$(srcdir)/ui/common/LineEdit.cpp \
$(srcdir)/ui/resource/AvConvTranscodeStreamResource.cpp \
$(srcdir)/ui/resource/CoverResource.cpp \
- $(srcdir)/ui/video/VideoWidget.cpp \
- $(srcdir)/ui/video/VideoDatabaseWidget.cpp \
- $(srcdir)/ui/video/VideoMediaPlayerWidget.cpp \
- $(srcdir)/ui/video/VideoParametersDialog.cpp \
$(srcdir)/ui/settings/Settings.cpp \
$(srcdir)/ui/settings/SettingsAccountFormView.cpp \
$(srcdir)/ui/settings/SettingsAudioFormView.cpp \
@@ -65,51 +51,14 @@ lms_SOURCES = \
$(srcdir)/ui/settings/SettingsUserFormView.cpp \
$(srcdir)/ui/settings/SettingsUsers.cpp
-if LMSAPI
+if VIDEO
lms_SOURCES += \
- $(srcdir)/lms-api/server/Connection.cpp \
- $(srcdir)/lms-api/server/ConnectionManager.cpp \
- $(srcdir)/lms-api/server/AudioCollectionRequestHandler.cpp \
- $(srcdir)/lms-api/server/AuthRequestHandler.cpp \
- $(srcdir)/lms-api/server/MediaRequestHandler.cpp \
- $(srcdir)/lms-api/server/RequestHandler.cpp \
- $(srcdir)/lms-api/server/Server.cpp \
- $(srcdir)/service/LmsAPIServerService.cpp
-
-nodist_lms_SOURCES = \
- $(builddir)/auth.pb.cc \
- $(builddir)/auth.pb.h \
- $(builddir)/collection.pb.cc \
- $(builddir)/collection.pb.h \
- $(builddir)/media.pb.cc \
- $(builddir)/media.pb.h \
- $(builddir)/messages.pb.cc \
- $(builddir)/messages.pb.h
-
-BUILT_SOURCES = \
- $(builddir)/auth.pb.cc \
- $(builddir)/auth.pb.h \
- $(builddir)/collection.pb.cc \
- $(builddir)/collection.pb.h \
- $(builddir)/media.pb.cc \
- $(builddir)/media.pb.h \
- $(builddir)/messages.pb.cc \
- $(builddir)/messages.pb.h
-
-MOSTLYCLEANFILES = \
- $(builddir)/auth.pb.cc \
- $(builddir)/auth.pb.h \
- $(builddir)/collection.pb.cc \
- $(builddir)/collection.pb.h \
- $(builddir)/media.pb.cc \
- $(builddir)/media.pb.h \
- $(builddir)/messages.pb.cc \
- $(builddir)/messages.pb.h
-
-%.pb.cc %.pb.h: $(top_srcdir)/lms-api/proto/%.proto
- $(PROTOC) --proto_path=$(top_srcdir)/lms-api/proto/ --cpp_out=$(builddir)/ $^
-
+ $(srcdir)/ui/video/VideoWidget.cpp \
+ $(srcdir)/ui/video/VideoDatabaseWidget.cpp \
+ $(srcdir)/ui/video/VideoMediaPlayerWidget.cpp \
+ $(srcdir)/ui/video/VideoParametersDialog.cpp
endif
-lms_CXXFLAGS=-DBOOST_LOG_DYN_LINK -std=c++11 -Wall -I$(top_srcdir)/third-party -I$(srcdir)/ui -I$(srcdir)/lms-api
+lms_CXXFLAGS=-std=c++11 -Wall -I$(top_srcdir)/third-party -I$(srcdir)/ui $(MAGICKXX_CFLAGS)
+lms_LDADD=$(MAGICKXX_LIBS)
diff --git a/src/av/AvInfo.cpp b/src/av/AvInfo.cpp
new file mode 100644
index 00000000..68390e30
--- /dev/null
+++ b/src/av/AvInfo.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2015 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#include
+
+#include "logger/Logger.hpp"
+
+#include "AvInfo.hpp"
+
+namespace Av {
+
+static std::string streamType_to_string(Stream::Type type)
+{
+ switch (type)
+ {
+ case Stream::Type::Audio: return "audio";
+ case Stream::Type::Video: return "video";
+ case Stream::Type::Subtitle: return "subtitle";
+ }
+
+ return "unknown";
+}
+
+static std::string averror_to_string(int error)
+{
+ std::array buf = {0};
+
+ if (av_strerror(error, buf.data(), buf.size()) == 0)
+ return std::string(&buf[0]);
+ else
+ return "Unknown error";
+}
+
+
+void AvInit()
+{
+ /* register all the codecs */
+ avcodec_register_all();
+ av_register_all();
+ LMS_LOG(AV, INFO) << "avcodec version = " << avcodec_version();
+}
+
+
+
+
+MediaFile::MediaFile(const boost::filesystem::path& p)
+: _p(p), _context(nullptr)
+{
+}
+
+MediaFile::~MediaFile()
+{
+ if (_context != nullptr)
+ avformat_close_input(&_context);
+}
+
+bool
+MediaFile::open(void)
+{
+ if (_context != nullptr)
+ throw std::logic_error("inputfile '" + _p.string() + "' already open");
+
+ int error = avformat_open_input(&_context, _p.string().c_str(), nullptr, nullptr);
+ if (error < 0)
+ {
+ LMS_LOG(AV, ERROR) << "Cannot open '" << _p.string() << "', avformat_open_input returned " << averror_to_string(error);
+ return false;
+ }
+
+ return true;
+}
+
+bool
+MediaFile::scan(void)
+{
+ if (_context == nullptr)
+ throw std::logic_error("inputfile '" + _p.string() + "' not open");
+
+ int error = avformat_find_stream_info(_context, nullptr);
+ if (error < 0)
+ {
+ LMS_LOG(AV, ERROR) << "Cannot find stream information: '" << averror_to_string(error);
+ return false;
+ }
+
+ return true;
+}
+
+boost::posix_time::time_duration
+MediaFile::getDuration() const
+{
+ if (_context == nullptr)
+ throw std::logic_error("inputfile '" + _p.string() + "' not open");
+
+ if (static_cast(_context->duration) != AV_NOPTS_VALUE )
+ return boost::posix_time::seconds(_context->duration / AV_TIME_BASE);
+ else
+ return boost::posix_time::seconds(0); // TODO, do something better?
+}
+
+void
+getMetaDataFromDictionnary(AVDictionary* dictionnary, std::map& res)
+{
+ if (!dictionnary)
+ return;
+
+ AVDictionaryEntry *tag = NULL;
+ while ((tag = av_dict_get(dictionnary, "", tag, AV_DICT_IGNORE_SUFFIX)))
+ {
+ res.insert( std::make_pair(tag->key, tag->value));
+ }
+}
+
+std::map
+MediaFile::getMetaData(void)
+{
+ if (_context == nullptr)
+ throw std::logic_error("inputfile '" + _p.string() + "' not open");
+
+ std::map res;
+
+ getMetaDataFromDictionnary(_context->metadata, res);
+
+ // HACK for OGG files
+ // If we did not find tags, search metadata in streams
+ if (res.empty())
+ {
+ for (std::size_t i = 0; i < _context->nb_streams; ++i)
+ {
+ getMetaDataFromDictionnary(_context->streams[i]->metadata, res);
+
+ if (!res.empty())
+ break;
+ }
+ }
+
+ return res;
+}
+
+std::vector
+MediaFile::getStreams(Stream::Type type) const
+{
+ if (_context == nullptr)
+ throw std::logic_error("inputfile '" + _p.string() + "' not open");
+
+ std::vector res;
+
+ for (std::size_t i = 0; i < _context->nb_streams; ++i)
+ {
+ AVStream* avstream = _context->streams[i];
+
+ // Skip attached pics
+ if (avstream->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ continue;
+
+ if (avstream->codec == nullptr)
+ {
+ LMS_LOG(AV, ERROR) << "Skipping stream " << i << " since no codec is set";
+ continue;
+ }
+
+ if (type == Stream::Type::Audio && avstream->codec->codec_type != AVMEDIA_TYPE_AUDIO)
+ continue;
+ else if (type == Stream::Type::Video && avstream->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+ continue;
+ else if (type == Stream::Type::Subtitle && avstream->codec->codec_type != AVMEDIA_TYPE_SUBTITLE)
+ continue;
+
+ Stream stream;
+
+ stream.id = i; // or use stream->id ?
+ stream.type = type;
+ stream.bitrate = avstream->codec->bit_rate;
+
+ {
+ std::array buf = {0};
+ avcodec_string(buf.data(), buf.size(), avstream->codec, 0);
+
+ stream.desc = buf.data();
+ }
+
+ res.push_back(stream);
+ }
+
+ return res;
+}
+
+int
+MediaFile::getBestStreamId(Stream::Type type) const
+{
+ if (_context == nullptr)
+ throw std::logic_error("inputfile '" + _p.string() + "' not open");
+
+ enum AVMediaType avMediaType;
+
+ switch (type)
+ {
+ case Stream::Type::Audio: avMediaType = AVMEDIA_TYPE_AUDIO; break;
+ case Stream::Type::Video: avMediaType = AVMEDIA_TYPE_VIDEO; break;
+ case Stream::Type::Subtitle: avMediaType = AVMEDIA_TYPE_SUBTITLE; break;
+ default:
+ return -1;
+ }
+
+ int res = av_find_best_stream(_context,
+ avMediaType,
+ -1, // Auto
+ -1, // Auto
+ NULL,
+ 0);
+ if (res < 0)
+ {
+ LMS_LOG(AV, ERROR) << "Cannot find best stream for type " << streamType_to_string(type);
+ return -1;
+ }
+
+ return res;
+}
+
+bool
+MediaFile::hasAttachedPictures(void) const
+{
+ for (std::size_t i = 0; i < _context->nb_streams; ++i)
+ {
+ if (_context->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ return true;
+ }
+
+ return false;
+}
+
+std::vector
+MediaFile::getAttachedPictures(std::size_t nbMaxPictures) const
+{
+ if (_context == nullptr)
+ throw std::logic_error("inputfile '" + _p.string() + "' not open");
+
+ static const std::map codecMimeMap =
+ {
+ { AV_CODEC_ID_BMP, "image/x-bmp" },
+ { AV_CODEC_ID_GIF, "image/gif" },
+ { AV_CODEC_ID_MJPEG, "image/jpeg" },
+ { AV_CODEC_ID_PNG, "image/png" },
+ { AV_CODEC_ID_PNG, "image/x-png" },
+ { AV_CODEC_ID_PPM, "image/x-portable-pixmap" },
+ };
+
+ std::vector pictures;
+
+ for (std::size_t i = 0; i < _context->nb_streams; ++i)
+ {
+ AVStream *avstream = _context->streams[i];
+
+ // Skip attached pics
+ if (!(avstream->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ continue;
+
+ if (avstream->codec == nullptr)
+ {
+ LMS_LOG(AV, ERROR) << "Skipping stream " << i << " since no codec is set";
+ continue;
+ }
+
+ Picture picture;
+
+ auto itMime = codecMimeMap.find(avstream->codec->codec_id);
+ if (itMime != codecMimeMap.end())
+ {
+ picture.mimeType = itMime->second;
+ }
+ else
+ {
+ picture.mimeType = "application/octet-stream";
+ LMS_LOG(AV, ERROR) << "CODEC ID " << avstream->codec->codec_id << " not handled in mime type conversion";
+ }
+
+ AVPacket pkt = avstream->attached_pic;
+
+ std::copy(pkt.data, pkt.data + pkt.size, std::back_inserter(picture.data));
+
+ pictures.push_back( picture );
+
+ if (pictures.size() >= nbMaxPictures)
+ break;
+ }
+
+ return pictures;
+}
+
+} // namespace Av
diff --git a/src/av/AvInfo.hpp b/src/av/AvInfo.hpp
new file mode 100644
index 00000000..377fd6fd
--- /dev/null
+++ b/src/av/AvInfo.hpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+/* This file contains some classes in order to get info from file using the libavconv */
+
+#ifndef AV_INFO_HPP
+#define AV_INFO_HPP
+
+extern "C"
+{
+#define __STDC_CONSTANT_MACROS
+#include
+#include
+#include
+}
+
+#include
+#include
+#include
+#include