Light Media Scanner

LMS(Light Media Scanner)는 임베디드 시스템에 사용하기 위한 가벼운 미디어 스캐너이다.

디렉토리를 최적화된 방법으로 재귀적으로 스캔하고, Child 프로세스에서 파서를 처리하여 파서에 문제가 발생했을 때 메인 프로세스가 종료되지 않게 한다. 파서는 Shared Object 형태의 플러그인이며, 스캐너를 다시 컴파일할 필요 없이 쉽게 추가할 수 있다.

SQLite3를 사용하여 파일의 mtime 관련 정보를 저장하고 files라는 마스터 테이블에 파일 id를 관리한다. 애플리케이션은 SQLite3 데이터베이스에 엑세스 하여 스캔 된 미디어에 대한 모든 정보를 얻을 수 있다. 사용자는 SQLite3 엑세스 라이브러리(Python의 SQLObject, SQLAlchemy 및 Storm, Ruby의 Sequel 등)을 모두 사용할 수 있다.

Table: files

이 테이블은 파일 시스템 엔트리와 연관된 정보들, 수정 시간, 추가 혹은 삭제 시간, byte 크기 및 경로를 제공한다.

Columns:

  • id: 파일을 식별하는 고유한 값. 새로운 엔트리가 생성되면 자동으로 증가.
  • path: 파일의 전체 경로.
  • mtime: stat(2) st_mtime에 따른 파일의 마지막 수정 시간.
  • dtime: 파일이 더 이상 파일 시스템에 존재하지 않는 경우, lms_check()를 호출한 시간. 파일이 파일 시스템에 존재하면 이 필드의 값은 0.
  • itime: 파일이 데이터베이스에 추가된 시간. “오늘 추가된 파일” 등을 표시할 때 유용.
  • size: stat(2) st_size에 따른 파일의 byte 크기.
  • update_id: 마지막으로 파일을 수정했을 때의 update_id. 관련 내용은 lms_internal 테이블 참조.

Examples:

  • 모든 파일의 경로 출력:
    SELECT path FROM files;
    
  • 파일 시스템에 존재하는 모든 파일의 경로 출력:
    SELECT path FROM files WHERE dtime = 0;
    
  • 지난 주 이전에 삭제된 모든 파일의 경로 출력($LASTWEEK는 현재 Unix 시간에서 7 * 24 * 60 * 60을 뺀 값):
    SELECT path FROM files WHERE dtime > 0 AND dtime <= $LASTWEEK;
    
  • 파일 시스템에 존재하는 파일 중 오늘 추가된 파일의 경로 출력($TODAY는 오늘 0시 0분의 Unix 시간 값):
    SELECT path FROM files WHERE dtime = 0 AND itime >= $TODAY;
    

Note:

사용 가능한 미디어를 질의할 때는 항상 (dtime = 0)를 포함 해야 한다. LightMediaScanner는 파일 시스템에서 파일이 삭제 되어도 데이터베이스에서 엔트리를 삭제하지 않고, 파일이 삭제 되었음을 표시하는 플래그를 설정한다(dtime = time(NULL);). 이 동작은 이동식 미디어가 해제 후 재연결 되었을 때, path, mtimesize가 동일한 파일을 빠르게 복구할 수 있게 해준다.

Table: images

이미지 엔트리와 해당 속성들을 가지는 테이블. files 테이블과 JOIN을 수행하여 파일 속성들을 얻을 수 있다.

Columns:

  • id: 파일을 식별하는 고유한 값. files.id 설명 참조.
  • title: 타이틀(없으면 파일 이름으로부터 생성).
  • artist: 아티스트.
  • date: 생성 시간(Unix-time).한
  • width: 너비(pixel).
  • height: 높이(pixel).
  • orientation: image intended display orientation, EXIF Orientation과 동일.
  • gps_lat: GPS 위도 값(degree).
  • gps_long: GPS 경도(degree).
  • gps_alt: GPS 고도(meter).
  • dlna_profile: 이미지가 DLNA 프로파일과 일치하면 이 속성이 설정됨.
  • dlna_mime: 이미지가 DLNA MIME 타입과 일치하면 이 속성이 설정됨.

Examples:

  • 파일 시스템에 존재하는 모든 이미지 파일의 경로 출력:
    SELECT files.path
    FROM images, files
    WHERE files.id = images.id AND files.dtime = 0;
    
  • 파일 시스템에 존재하는 이미지 파일 중 dlna_profile이 “image/jpeg”인 파일의 경로, 너비 및 폭 출력:
    SELECT files.path, images.width, images.height
    FROM images, files
    WHERE files.id = images.id AND files.dtime = 0 AND dlna_mime = 'image/jpeg'
    

Tables: audios, audio_albums, audio_artists and audio_genres

오디오 파일 관련 테이블. 필수로 필요한 것은 audio 테이블이며, audio에서 앨범(audio_albums 참조), 아티스트(audio_artists 참조) 및 장르(audio_genres)를 가질 수 있다. 파일 속성들은 files 테이블과 JOIN을 수행하여 얻을 수 있다.

audios Columns :

  • id: 파일을 식별하는 고유한 값. files.id 설명 참조.
  • title: 타이틀(없으면 파일 이름으로부터 생성).
  • album_id: 앨범을 식별하는 고유한 값. audio_albums 테이블과 연관됨.
  • artist_id: 아티스트를 식별하는 고유한 값. audio_artists 테이블과 연관됨.
  • genre_id: 장르를 식별하는 고유한 값. audio_genres 테이블과 연관됨.
  • trackno: 앨범 내의 트랙 번호.
  • rating: 사용자 평점(“별점” 혹은 “좋아요” 등을 의미. 연령 제한 등급과 혼동하지 말것).
  • playcnt: 플레이 횟수.
  • length: 길이(second).
  • container: 파일 타입(“asf”, “mp4” 등).
  • codec: 오디오 코덱(“mpeg1layer3”, “mpeg4aac-main” 등).
  • channels: 오디오 채널 갯수(모노는 1, 스테레오는 2 등).
  • sampling_rate: 오디오 샘플링 속도(44100, 48000 등).
  • bitrate: 샘플 당 평균 bit 수(32000, 8000 등).
  • dlna_profile: 오디오가 DLNA 프로파일과 일치하면 이 속성이 설정됨.
  • dlna_mime: 오디오가 DLNA MIME 타입과 일치하면 이 속성이 설정됨.

audio_artists Columns:

  • id: 아티스트를 식별하는 고유한 값. audios.artist_id 설명 참조.
  • name: 아티스트 이름.

audio_albums Columns:

  • id: 앨범을 식별하는 고유한 값. audios.album_id 설명 참조.
  • artist_id: 아티스트를 식별하는 고유한 값. audio_artists 테이블과 연관됨.
  • name: 앨범 이름.

audio_genres Columns:

  • id: 장르를 식별하는 고유한 값. audios.genre_id 설명 참조.
  • name: 장르 이름.

Examples:

  • 파일 시스템에 존재하는 모든 오디오 파일의 경로 출력:
    SELECT files.path
    FROM audios, files
    WHERE files.id = audios.id AND files.dtime = 0;
    
  • 파일 시스템에 존재하는 모든 오디오 파일의 경로, 타이틀, 아티스트, 앨범 및 장르 이름 출력:
    SELECT files.path, audios.title, audio_artists.name, audio_albums.name, audio_genres.name
    FROM audios, files, audio_artists, audio_albums, audio_genres
    WHERE files.id = audios.id AND files.dtime = 0
       AND audio_artists.id = audios.artist_id
       AND audio_albums.id = audios.album_id
       AND audio_genres.id = audios.genre_id
    

Table: videos, videos_audios, videos_subtitles, videos_videos

비디오 파일 관련 테이블. 필수로 필요한 것은 video 테이블이며, video에서 여러 개의 비디오, 오디오 및 자막 스트림을 가질 수 있다. 파일 속성들은 files 테이블과 JOIN을 수행하여 얻을 수 있다.

videos Columns:

  • id: 파일을 식별하는 고유한 값. files.id 설명 참조.
  • title: 타이틀(없으면 파일 이름으로부터 생성).
  • artist: 아티스트.
  • length: 길이(second).
  • container: 파일 타입(“asf”, “mp4” 등).
  • dlna_profile: 비디오가 DLNA 프로파일과 일치하면 이 속성이 설정됨.
  • dlna_mime: 비디오가 DLNA MIME 타입과 일치하면 이 속성이 설정됨.

videos_audios Columns:

  • id: 오디오 스트림을 식별하는 고유한 값.
  • video_id: 비디오를 식별하는 고유한 값. videos.id 설명 참조.
  • stream_id: 비디오 내의 스트림 식별값.
  • lang: 언어(“en”, “pt”, “es” 등).
  • codec: 오디오 스트림 코덱(“mpeg1layer3”, “mpeg4aac-main” 등).
  • channels: 오디오 채널 갯수(모노는 1, 스테레오는 2 등).
  • sampling_rate: 오디오 샘플링 속도(44100, 48000 등).
  • bitrate: 샘플 당 평균 bit 수(32000, 8000 등).

videos_subtitles Columns:

  • id: 자막 스트림을 식별하는 고유한 값.
  • video_id: 비디오를 식별하는 고유한 값. videos.id 설명 참조.
  • stream_id: 비디오 내의 스트림 식별값.
  • lang: 언어(“en”, “pt”, “es” 등).
  • codec: 자막 스트림 코덱(“srt”, “ssa”, “sub” 등).

videos_videos Columns:

  • id: 비디오 스트림을 식별하는 고유한 값.
  • video_id: 비디오를 식별하는 고유한 값. videos.id 설명 참조.
  • stream_id: 비디오 내의 스트림 식별값.
  • lang: 언어(“en”, “pt”, “es” 등).
  • codec: 비디오 스트림 코덱(“mpeg4-simple-l1”, “mpeg4-main-l4” 등).
  • aspect_ratio: 문자열로 인코딩 된 화면 비율(“4:3”, “16:9” 등).
  • bitrate: 샘플 당 평균 bit 수(500000, 800000).
  • framerate: 초당 프레임 수(30.0, 29.94, 60.0 등).
  • interlaced: 인터레이스인 경우 1.
  • width: 너비(pixel).
  • height: 높이(pixel).

Examples:

  • 파일 시스템에 존재하는 모든 비디오 파일의 경로 출력:
    SELECT files.path FROM videos, files WHERE files.id = videos.id AND files.dtime = 0;
    
  • 비디오에 있는 모든 오디오 스트림 출력:
    SELECT videos_audios.id, videos_audios.stream_id, videos_audios.lang, videos_audios.codec,
        videos_audios.channels, videos_audios.sampling_rate, videos_audios.bitrate
    FROM videos_audios WHERE videos_audios.id = $VIDEOID
    

Table: lms_internal

내부적으로 테이블들의 버전을 관리하기 위한 테이블. 어떤 테이블이 수정되면 이 테이블에서 해당 테이블의 버전이 수정된다.

Update ID

tab = 'update_id'는 전역 update_id 정수값을 가리키는 특별한 행이다. 이 정수값은 lms_process() 또는 lms_check() 함수가 데이터베이스를 수정하거나, 파일을 추가, 수정 및 삭제할 때마다 증가한다. 사용자는 이 값을 사용하여 컨텐츠를 동기화 할 수 있다.

컨텐츠를 동기화 하는 가장 단순한 방법은 데이터베이스에 질의할 때마다 전역 변수로 update_id 값을 저장하고, 이 전역 변수가 변경되면 모든 질의를 다시 실행하는 것이다.

보다 효율적인 방법은 데이터베이스 질의를 update_id > $OLD_UPDATE_ID로 제한하여 수행하고 결과를 이전 것과 병합하는 것이다. 이 방법을 위해서는 최소한 file.id를 저장해야 하며, 이를 사용하여 수정된 엔트리를 업데이트 하고, 파일이 파일 시스템에서 사라졌는지를 확인하기 위한 files.dtime을 읽고, 새로 추가된 결과가 정렬 기준에 맞게 적절하게 삽입되도록 할 수 있다.

Build

1 Configuration

./autogen.sh $CONFIGURE_FLAGS --prefix=/home/root/lms --with-dbus-services=/home/root/.local/share/dbus-1/services

2 Build

make

3 Install

make DESTDIR="$PWD/install" install

4 Result

install
└── home
    └── root
        ├── .local
        │   └── share
        │       └── dbus-1
        │           └── services
        │               └── org.lightmediascanner.service
        └── lms
            ├── bin
            │   ├── lightmediascannerctl
            │   └── lightmediascannerd
            ├── include
            │   ├── lightmediascanner.h
            │   ├── lightmediascanner_charset_conv.h
            │   ├── lightmediascanner_db.h
            │   ├── lightmediascanner_plugin.h
            │   └── lightmediascanner_utils.h
            └── lib
                ├── liblightmediascanner.la
                ├── liblightmediascanner.so -> liblightmediascanner.so.0.5.1
                ├── liblightmediascanner.so.0 -> liblightmediascanner.so.0.5.1
                ├── liblightmediascanner.so.0.5.1
                ├── lightmediascanner
                │   └── plugins
                │       ├── asf.la
                │       ├── asf.so
                │       ├── audio-dummy.la
                │       ├── audio-dummy.so
                │       ├── dummy.la
                │       ├── dummy.so
                │       ├── flac.la
                │       ├── flac.so
                │       ├── id3.la
                │       ├── id3.so
                │       ├── jpeg.la
                │       ├── jpeg.so
                │       ├── m3u.la
                │       ├── m3u.so
                │       ├── ogg.la
                │       ├── ogg.so
                │       ├── pls.la
                │       ├── pls.so
                │       ├── png.la
                │       ├── png.so
                │       ├── rm.la
                │       ├── rm.so
                │       ├── video-dummy.la
                │       ├── video-dummy.so
                │       ├── wave.la
                │       └── wave.so
                └── pkgconfig
                    └── lightmediascanner.pc

Database

기본 DB 경로

  • ~/.config/lightmediascannerd/db.sqlite3

SQLite3

select * from files;

DBus 서비스

  • /usr/share/dbus-1/services/org.lightmediascanner.service

DBus 서비스 정의 파일에서 LMS 데몬 경로 및 스캔을 위한 카테고리 디렉토리 지정

[D-BUS Service]
Name=org.lightmediascanner
Exec=/usr/bin/lightmediascannerd -D picture:/home/root/Pictures -D audio:/home/root/Music

Daemon

Options

Application Options:
  -p, --db-path=PATH                     Path to LightMediaScanner SQLit3 data base, defaults to "~/.config/lightmediascannerd/db.sqlite3".
  -c, --commit-interval=NUMBER           Execute SQL COMMIT after NUMBER files are processed, defaults to 100.
  -t, --slave-timeout=SECONDS            Number of seconds to wait for slave to reply, otherwise kills it. Defaults to 60.
  -d, --delete-older-than=DAYS           Delete from database files that have 'dtime' older than the given number of DAYS. If not specified LightMediaScanner will keep the files in the database even if they are gone from the file system and if they appear again and have the same 'mtime' and 'size' it will be restored ('dtime' set to 0) without the need to parse the file again (much faster). This is useful for removable media. Use a negative number to disable this behavior. Defaults to 30.
  -V, --vacuum                           Execute SQL VACUUM after every scan.
  -S, --startup-scan                     Execute full scan on startup.
  --omit-scan-progress                   Omit the ScanProgress signal during scans. This will avoid the overhead of D-Bus signal emission and may slightly improve the performance, but will make the listener user-interfaces less responsive as they won't be able to tell the user what is happening.
  -C, --charset=CHARSET                  Extra charset to use. (Multiple use)
  -P, --parser=CATEGORY:PARSER           Parsers to use, defaults to all. Format is 'category:parsername' or 'parsername' to apply parser to all categories. The special parsername 'all' declares all known parsers, while 'all-category' declares all parsers of that category. If one parser is provided, then no defaults are used, you can pre-populate all categories with their parsers by using --parser=all-category.
  -D, --directory=CATEGORY:DIRECTORY     Directories to use, defaults to FreeDesktop.Org standard. Format is 'category:directory' or 'path' to apply directory to all categories. The special directory 'defaults' declares all directories used by default for that category. If one directory is provided, then no defaults are used, you can pre-populate all categories with their directories by using --directory=defaults.

Controller

Usage

Usage:
	lms/bin/lightmediascannerctl <action>

Action is one of:
	status          print server properties and exit.
	monitor         monitor server and its properties.
	write-lock      try to get a write-lock and keep it while running.
	scan [params]   start scan. May receive parameters as a series of 
	                CATEGORY:PATH to limit scan.
	stop            stop ongoing scan.
	help            this message.

Status

lightmediascannerctl status

Scan

lightmediascannerctl scan

Scan 범위 지정

  • 데몬 실행 시 정의한 카테고리 디렉토리 및 그 하위 디렉토리만 설정 가능
lightmediascannerctl scan picture:/home/root/Pictures

References