aboutsummaryrefslogtreecommitdiff
path: root/xbmc/video/tags/VideoTagLoaderNFO.cpp
blob: c5e3b84539bc74a09d693402f4a207be0a3a13cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
 *  Copyright (C) 2005-2018 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#include "VideoTagLoaderNFO.h"

#include "FileItem.h"
#include "FileItemList.h"
#include "NfoFile.h"
#include "URL.h"
#include "filesystem/Directory.h"
#include "filesystem/StackDirectory.h"
#include "utils/FileUtils.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "utils/log.h"
#include "video/VideoInfoTag.h"

#include <utility>

using namespace XFILE;

CVideoTagLoaderNFO::CVideoTagLoaderNFO(const CFileItem& item,
                                       ADDON::ScraperPtr info,
                                       bool lookInFolder)
  : IVideoInfoTagLoader(item, std::move(info), lookInFolder)
{
  if (m_info && m_info->Content() == CONTENT_TVSHOWS && m_item.m_bIsFolder)
    m_path = URIUtils::AddFileToFolder(m_item.GetPath(), "tvshow.nfo");
  else
    m_path = FindNFO(m_item, lookInFolder);
}

bool CVideoTagLoaderNFO::HasInfo() const
{
  return !m_path.empty() && CFileUtils::Exists(m_path);
}

CInfoScanner::INFO_TYPE CVideoTagLoaderNFO::Load(CVideoInfoTag& tag,
                                                 bool prioritise,
                                                 std::vector<EmbeddedArt>*)
{
  CNfoFile nfoReader;
  CInfoScanner::INFO_TYPE result = CInfoScanner::NO_NFO;
  if (m_info && m_info->Content() == CONTENT_TVSHOWS && !m_item.m_bIsFolder)
    result = nfoReader.Create(m_path, m_info, m_item.GetVideoInfoTag()->m_iEpisode);
  else if (m_info)
    result = nfoReader.Create(m_path, m_info);

  if (result == CInfoScanner::FULL_NFO || result == CInfoScanner::COMBINED_NFO)
    nfoReader.GetDetails(tag, nullptr, prioritise);

  if (result == CInfoScanner::URL_NFO || result == CInfoScanner::COMBINED_NFO)
  {
    m_url = nfoReader.ScraperUrl();
    m_info = nfoReader.GetScraperInfo();
  }

  std::string type;
  switch(result)
  {
    case CInfoScanner::COMBINED_NFO:
      type = "mixed";
      break;
    case CInfoScanner::FULL_NFO:
      type = "full";
      break;
    case CInfoScanner::URL_NFO:
      type = "URL";
      break;
    case CInfoScanner::NO_NFO:
      type = "";
      break;
    case CInfoScanner::OVERRIDE_NFO:
      type = "override";
      break;
    default:
      type = "malformed";
  }
  if (result != CInfoScanner::NO_NFO)
    CLog::Log(LOGDEBUG, "VideoInfoScanner: Found matching {} NFO file: {}", type,
              CURL::GetRedacted(m_path));
  else
    CLog::Log(LOGDEBUG, "VideoInfoScanner: No NFO file found. Using title search for '{}'",
              CURL::GetRedacted(m_item.GetPath()));

  return result;
}

std::string CVideoTagLoaderNFO::FindNFO(const CFileItem& item,
                                        bool movieFolder) const
{
  std::string nfoFile;
  // Find a matching .nfo file
  if (!item.m_bIsFolder)
  {
    if (URIUtils::IsInRAR(item.GetPath())) // we have a rarred item - we want to check outside the rars
    {
      CFileItem item2(item);
      CURL url(item.GetPath());
      std::string strPath = URIUtils::GetDirectory(url.GetHostName());
      item2.SetPath(URIUtils::AddFileToFolder(strPath,
                                            URIUtils::GetFileName(item.GetPath())));
      return FindNFO(item2, movieFolder);
    }

    // grab the folder path
    std::string strPath = URIUtils::GetDirectory(item.GetPath());

    if (movieFolder && !item.IsStack())
    { // looking up by folder name - movie.nfo takes priority - but not for stacked items (handled below)
      nfoFile = URIUtils::AddFileToFolder(strPath, "movie.nfo");
      if (CFileUtils::Exists(nfoFile))
        return nfoFile;
    }

    // try looking for .nfo file for a stacked item
    if (item.IsStack())
    {
      // first try .nfo file matching first file in stack
      CStackDirectory dir;
      std::string firstFile = dir.GetFirstStackedFile(item.GetPath());
      CFileItem item2;
      item2.SetPath(firstFile);
      nfoFile = FindNFO(item2, movieFolder);
      // else try .nfo file matching stacked title
      if (nfoFile.empty())
      {
        std::string stackedTitlePath = dir.GetStackedTitlePath(item.GetPath());
        item2.SetPath(stackedTitlePath);
        nfoFile = FindNFO(item2, movieFolder);
      }
    }
    else
    {
      // already an .nfo file?
      if (URIUtils::HasExtension(item.GetPath(), ".nfo"))
        nfoFile = item.GetPath();
      // no, create .nfo file
      else
        nfoFile = URIUtils::ReplaceExtension(item.GetPath(), ".nfo");
    }

    // test file existence
    if (!nfoFile.empty() && !CFileUtils::Exists(nfoFile))
      nfoFile.clear();

    if (nfoFile.empty()) // final attempt - strip off any cd1 folders
    {
      URIUtils::RemoveSlashAtEnd(strPath); // need no slash for the check that follows
      CFileItem item2;
      if (StringUtils::EndsWithNoCase(strPath, "cd1"))
      {
        strPath.erase(strPath.size() - 3);
        item2.SetPath(URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(item.GetPath())));
        return FindNFO(item2, movieFolder);
      }
    }

    if (nfoFile.empty() && item.IsOpticalMediaFile())
    {
      CFileItem parentDirectory(item.GetLocalMetadataPath(), true);
      nfoFile = FindNFO(parentDirectory, true);
    }
  }
  // folders (or stacked dvds) can take any nfo file if there's a unique one
  if (item.m_bIsFolder || item.IsOpticalMediaFile() || (movieFolder && nfoFile.empty()))
  {
    // see if there is a unique nfo file in this folder, and if so, use that
    CFileItemList items;
    CDirectory dir;
    std::string strPath;
    if (item.m_bIsFolder)
      strPath = item.GetPath();
    else
      strPath = URIUtils::GetDirectory(item.GetPath());

    if (dir.GetDirectory(strPath, items, ".nfo", DIR_FLAG_DEFAULTS) && items.Size())
    {
      int numNFO = -1;
      for (int i = 0; i < items.Size(); i++)
      {
        if (items[i]->IsNFO())
        {
          if (numNFO == -1)
            numNFO = i;
          else
          {
            numNFO = -1;
            break;
          }
        }
      }
      if (numNFO > -1)
        return items[numNFO]->GetPath();
    }
  }

  return nfoFile;
}