Exemple #1
0
 /// <summary>
 /// クエリ文字列をSQL文に展開してPrepare
 /// </summary>
 /// <param name="queryText">クエリ文字列</param>
 /// <returns>プリペアドステートメントまたはNULL</returns>
 private SQLite3DB.STMT ExpandAndPrepareQueryText(string queryText)
 {
     SQLite3DB.STMT tmt = null;
     for (int i = 0; i < RETRY_COUNT; i++)
     {
         foreach (var dlg in QueryTextExpanders)
         {
             try
             {
                 tmt = PrepareForCreatePlaylistView(dlg(queryText));
                 break;
             }
             catch (NotSupportedException) { /* nothin to do */ }
             catch (ArgumentException) { /* nothin to do */ }
             catch (SQLite3DB.SQLite3Exception e) { Logger.Log(e); }
         }
         ;
         if (tmt != null)
         {
             break;
         }
         Thread.Sleep(RETRY_DELAY);
     }
     return(tmt);
 }
Exemple #2
0
 private Column[] LoadColumnDefinitionFromDB()
 {
     using (var db = this.Connect())
     {
         var colCount = 0;
         using (SQLite3DB.STMT tmt2 = db.Prepare("SELECT COUNT(*) FROM library_definition ;"))
         {
             tmt2.Evaluate((o) => colCount = int.Parse(o[0].ToString()));
         }
         if (colCount > 0)
         {
             var coldefs = new object[colCount][];
             db.FetchRowRange("library_definition", 0, colCount, coldefs);
             var columns = new List <Column>();
             foreach (var coldef in coldefs)
             {
                 columns.Add(new Column(
                                 Name: coldef[0].ToString(),
                                 LocalText: coldef[1].ToString(),
                                 type: (LibraryColumnType)int.Parse(coldef[2].ToString()),
                                 IsPrimaryKey: coldef[3].ToString() == "1",
                                 MappedTagField: coldef[4].ToString(),
                                 IsTextSearchTarget: coldef[5].ToString() == "1",
                                 OmitOnImport: coldef[6].ToString() == "1"));
             }
             return(columns.ToArray());
         }
     }
     return(null);
 }
Exemple #3
0
        /// <summary>
        /// トラックの情報をSTMTにBINDする
        /// </summary>
        /// <param name="stmt">BINDするSTMT</param>
        /// <param name="track">トラック情報</param>
        /// <param name="cols">データベースのカラムのリスト</param>
        private void BindTrackInfo(SQLite3DB.STMT stmt, LuteaAudioTrack track, Column[] cols)
        {
            stmt.Reset();
            string extension = (((track.file_ext == "CUE") && (track is CD.Track)) ? ((CD.Track)track).file_ext_CUESheet : track.file_ext).ToUpper();
            var    values    = cols
                               .Select(col =>
            {
                switch (col.Name)
                {
                case LibraryDBColumnTextMinimum.file_name: return(track.file_name);

                case LibraryDBColumnTextMinimum.file_title: return(track.file_title);

                case LibraryDBColumnTextMinimum.file_ext: return(extension);

                case LibraryDBColumnTextMinimum.file_size: return(track.file_size.ToString());

                case LibraryDBColumnTextMinimum.statDuration: return(((int)track.duration).ToString());

                case LibraryDBColumnTextMinimum.statChannels: return(track.channels.ToString());

                case LibraryDBColumnTextMinimum.statSamplingrate: return(track.freq.ToString());

                case LibraryDBColumnTextMinimum.statBitrate: return(track.bitrate.ToString());

                case LibraryDBColumnTextMinimum.statVBR: return("0");

                case LibraryDBColumnTextMinimum.infoCodec: return(track.codec.ToString());

                case LibraryDBColumnTextMinimum.infoCodec_sub: return(extension);

                case LibraryDBColumnTextMinimum.infoTagtype: return("0");

                case LibraryDBColumnTextMinimum.gain: return("0");

                case LibraryDBColumnTextMinimum.modify: return(MusicLibrary.currentTimestamp.ToString());

                default:
                    if (!track.tag.Exists((e) => e.Key == col.MappedTagField))
                    {
                        return("");
                    }
                    if (track.tag.First((e) => e.Key == col.MappedTagField).Value == null)
                    {
                        return("");
                    }
                    var tagValue = track.tag.First((e) => e.Key == col.MappedTagField).Value.ToString();
                    // DATEの表現形式を正規化して格納する
                    return(col.MappedTagField == "DATE"
                                ? normalizeDateString(tagValue) ?? tagValue
                                : tagValue);
                }
            });

            for (int i = 0; i < cols.Length; i++)
            {
                stmt.Bind(i + 1, values.ElementAt(i));
            }
        }
Exemple #4
0
        /// <summary>
        /// プレイリストの行を取得する(キャッシュ付き)
        /// </summary>
        /// <param name="index">行番号</param>
        /// <returns>行の内容,またはNULL</returns>
        public object[] GetPlaylistRow(int index)
        {
            if (index < 0)
            {
                return(null);
            }
            // このメソッドの呼び出し中にcacheの参照が変わる可能性があるので、最初に参照をコピーする
            // 一時的に古いcacheの内容を吐いても問題ないので、mutexで固めるほどではない
            var _cache = PlaylistCache;

            if (_cache == null)
            {
                return(null);
            }
            if (_cache.Length <= index)
            {
                return(null);
            }
            object[] value = null;
            for (int i = 0; i < RETRY_COUNT; i++)
            {
                if (_cache[index] == null)
                {
                    try
                    {
                        lock (FetchRowStmtLock)
                        {
                            if (FetchRowStmt == null)
                            {
                                FetchRowStmt = LibraryDB.Prepare("SELECT * FROM list WHERE file_name = (SELECT file_name FROM " + PlaylistTableName + " WHERE ROWID=?);");
                            }
                            FetchRowStmt.Bind(1, (index + 1).ToString());
                            _cache[index] = FetchRowStmt.EvaluateFirstROW();
                        }
                    }
                    catch (SQLite3DB.SQLite3Exception) { }
                }
                if ((_cache[index] == null) || (_cache[index].Length == 0) || (_cache[index][0] == null))
                {
                    _cache[index] = null;
                    Thread.Sleep(1);
                }
                else
                {
                    break;
                }
            }
            value = _cache[index];
            if (value == null || value.Length == 0)
            {
                return(null);
            }
            return(value);
        }
Exemple #5
0
 /// <summary>
 /// プレイリスト内の行を取得するプリペアドステートメントを破棄
 /// </summary>
 private void DisposeFetchStmt()
 {
     lock (FetchRowStmtLock)
     {
         if (FetchRowStmt != null)
         {
             FetchRowStmt.Dispose();
             FetchRowStmt = null;
         }
     }
 }
Exemple #6
0
 /// <summary>
 /// ライブラリのfile_nameカラムがfile_nameまたはfile_name+" "に一致するもののmodifyの値をDateTime型で返す。
 /// file_nameがライブラリにない場合はDateTime(0)を返す。
 /// </summary>
 /// <param name="lastModifySTMT"></param>
 /// <param name="file_name"></param>
 /// <returns></returns>
 private DateTime LastModifyDatetime(SQLite3DB.STMT lastModifySTMT, string file_name)
 {
     // SQLiteがDBがロックされてたとかで失敗する場合があるのでリトライする
     for (int i = 0; i < 10; i++)
     {
         try
         {
             lastModifySTMT.Reset();
             lastModifySTMT.Bind(1, file_name);
             lastModifySTMT.Bind(2, file_name + " ");
             var result = lastModifySTMT.EvaluateAll();
             if (result.Length == 0)
             {
                 return(new DateTime(0));
             }
             return(Util.Util.timestamp2DateTime(long.Parse(result[0][0].ToString())));
         }
         catch (SQLite3DB.SQLite3Exception)
         {
             Thread.Sleep(1);
         }
     }
     return(new DateTime(0));
 }
Exemple #7
0
        /// <summary>
        /// CUEとCUE以外を順に解析を行う
        /// </summary>
        /// <param name="filenameOfCUEs"></param>
        /// <param name="filenameOfOthers"></param>
        /// <param name="threadLocalResults"></param>
        /// <param name="selectModifySTMT"></param>
        private void DoAnalyze(IEnumerable <string> filenameOfCUEs, IEnumerable <string> filenameOfOthers, List <LuteaAudioTrack> threadLocalResults, SQLite3DB.STMT selectModifySTMT)
        {
            // CUEファイルを処理
            if (TypesToImport.HasFlag(ImportableTypes.CUE))
            {
                foreach (var cuefile in filenameOfCUEs)
                {
                    try
                    {
                        AnalyzeCUE(cuefile, threadLocalResults, selectModifySTMT);
                    }
                    catch (System.IO.IOException ex) { Logger.Error(ex.ToString()); }
                }
            }

            // 全てのファイルを処理
            foreach (var file in filenameOfOthers)
            {
                try
                {
                    AnalyzeStreamFile(file, threadLocalResults, selectModifySTMT);
                }
                catch (System.IO.IOException ex) { Logger.Error(ex.ToString()); }
            }
        }
Exemple #8
0
        /// <summary>
        /// 単体の音楽ファイルを解析する
        /// </summary>
        /// <param name="file_name">ファイル名</param>
        /// <param name="threadLocalResultQueue">スレッド固有の解析結果</param>
        /// <param name="lastModifySTMT">modifyを取得するプリペアドステートメント</param>
        private void AnalyzeStreamFile(string file_name, List <LuteaAudioTrack> threadLocalResultQueue, SQLite3DB.STMT lastModifySTMT)
        {
            // 既に処理済みの場合はreturn
            if (AlreadyAnalyzedFiles.Contains(file_name))
            {
                return;
            }

            // 処理済みファイルに追加
            lock (AlreadyAnalyzedFiles)
            {
                AlreadyAnalyzedFiles.Add(file_name);
            }
            if (LastModifyDatetime(lastModifySTMT, file_name) > new System.IO.FileInfo(file_name).LastWriteTime&& IsFastMode)
            {
                return;
            }
            var tag = MetaTag.readTagByFilename(file_name, false);

            if (tag == null)
            {
                return;
            }
            var cue = tag.Find(match => match.Key.ToUpper() == "CUESHEET");

            if (cue.Key != null)
            {
                var cd = InternalCUEReader.Read(file_name, true);
                if (cd == null)
                {
                    Logger.Error("CUESHEET is embedded. But, it has error. " + file_name);
                    return;
                }
                threadLocalResultQueue.AddRange(cd.tracks.Cast <LuteaAudioTrack>());
            }
            else
            {
                // PERFORMERがないとき、ARTISTをPERFORMERとして扱う
                if (tag.Find((e) => { return(e.Key == "PERFORMER"); }).Value == null)
                {
                    var artist = tag.Find((e) => { return(e.Key == "ARTIST"); });
                    if (artist.Value != null)
                    {
                        tag.Add(new KeyValuePair <string, object>("PERFORMER", artist.Value));
                    }
                }
                var tr = new LuteaAudioTrack()
                {
                    file_name = file_name, file_size = new System.IO.FileInfo(file_name).Length
                };
                if (tag.Exists(_ => _.Key == "__X-LUTEA-CHANS__") && tag.Exists(_ => _.Key == "__X-LUTEA-FREQ__") && tag.Exists(_ => _.Key == "__X-LUTEA-DURATION__"))
                {
                    tr.duration = int.Parse(tag.Find(_ => _.Key == "__X-LUTEA-DURATION__").Value.ToString());
                    tr.channels = int.Parse(tag.Find(_ => _.Key == "__X-LUTEA-CHANS__").Value.ToString());
                    tr.freq     = int.Parse(tag.Find(_ => _.Key == "__X-LUTEA-FREQ__").Value.ToString());
                }
                else
                {
                    try
                    {
                        using (var strm = DecodeStreamFactory.CreateFileStreamPrimitive(file_name))
                        {
                            tr.duration = (int)strm.LengthSec;
                            tr.channels = (int)strm.Chans;
                            tr.freq     = (int)strm.Freq;
                        }
                    }
                    catch (ArgumentException ex)
                    {
                        Logger.Error("cannot open file (by BASS)" + file_name);
                        Logger.Debug(ex);
                    }
                }
                tr.tag = tag;
                if (tr.file_ext == "M4A")
                {
                    if (tag.Exists(_ => (_.Key == "PURCHASE DATE") || (_.Key == "PURCHASED")))
                    {
                        if ((TypesToImport & ImportableTypes.M4A_iTunes) == 0)
                        {
                            return;
                        }
                    }
                    else if (tr.codec == H2k6Codec.ALAC)
                    {
                        if ((TypesToImport & ImportableTypes.M4A_ALAC) == 0)
                        {
                            return;
                        }
                    }
                    else
                    {
                        if ((TypesToImport & ImportableTypes.M4A) == 0)
                        {
                            return;
                        }
                    }
                }
                threadLocalResultQueue.Add(tr);
            }
        }
Exemple #9
0
        /// <summary>
        /// CUEシートを解析する
        /// </summary>
        /// <param name="file_name">ファイル名</param>
        /// <param name="lastModifySTMT">modifyを取得するプリペアドステートメント</param>
        private void AnalyzeCUE(string file_name, List <LuteaAudioTrack> threadLocalResults, SQLite3DB.STMT lastModifySTMT)
        {
            // 既に処理済みの場合はreturn
            if (AlreadyAnalyzedFiles.Contains(file_name))
            {
                return;
            }

            // 処理済みファイルに追加
            lock (AlreadyAnalyzedFiles)
            {
                AlreadyAnalyzedFiles.Add(file_name);
            }

            // ファイルを解析
            var cd = CUEReader.ReadFromFile(file_name, true);

            if (cd == null)
            {
                return;
            }

            string lastCheckedFilename       = null;
            bool   lastCheckedFileShouldSkip = false;
            bool   modifyed = LastModifyDatetime(lastModifySTMT, file_name) <= new System.IO.FileInfo(file_name).LastWriteTime;

            foreach (CD.Track tr in cd.tracks)
            {
                if (tr.file_name_CUESheet == "")
                {
                    continue;
                }

                // 実体ストリームが存在しない、またはCUESHEETが埋め込まれているなら、.cueファイルとしてのインポートはスキップする。
                if (lastCheckedFilename != tr.file_name_CUESheet)
                {
                    lastCheckedFilename       = tr.file_name_CUESheet;
                    lastCheckedFileShouldSkip = false;

                    if (!System.IO.File.Exists(tr.file_name_CUESheet))
                    {
                        lastCheckedFileShouldSkip = true;
                    }

                    // CUEシートが埋め込まれているならスキップ
                    var tagInRealStream = MetaTag.readTagByFilename(tr.file_name_CUESheet, false);
                    if (tagInRealStream != null && (tagInRealStream.Exists(e => e.Key == "CUESHEET")))
                    {
                        lastCheckedFileShouldSkip = true;
                    }
                }
                // ストリームのタグにCUESHEETがある時はなにもしない
                if (lastCheckedFileShouldSkip)
                {
                    continue;
                }

                lock (AlreadyAnalyzedFiles)
                {
                    AlreadyAnalyzedFiles.AddRange(cd.tracks.Select(_ => _.file_name_CUESheet));
                }
                if (modifyed || !IsFastMode)
                {
                    threadLocalResults.Add(tr);
                }
            }
        }