Passed
Push — master ( 8b334f...d95312 )
by Darko
11:24
created

BaseVideoProvider::getAliases()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
c 0
b 0
f 0
dl 0
loc 22
rs 8.8333
cc 7
nc 10
nop 2
1
<?php
2
3
/**
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program (see LICENSE.txt in the base directory.  If
16
 * not, see:
17
 *
18
 * @link      <http://www.gnu.org/licenses/>.
19
 *
20
 * @author    niel
21
 * @copyright 2015 nZEDb
22
 */
23
24
namespace App\Services\TvProcessing\Providers;
25
26
use App\Models\TvInfo;
27
use App\Models\Video;
28
use App\Models\VideoAlias;
29
use Illuminate\Support\Facades\Cache;
30
31
/**
32
 * Parent class for TV/Film and any similar classes to inherit from.
33
 */
34
abstract class BaseVideoProvider
35
{
36
    // Video Type Identifiers
37
    protected const TYPE_TV = 0; // Type of video is a TV Programme/Show
38
39
    protected const TYPE_FILM = 1; // Type of video is a Film/Movie
40
41
    protected const TYPE_ANIME = 2; // Type of video is a Anime
42
43
    public bool $echooutput;
44
45
    /**
46
     * @var array sites	The sites that we have an ID columns for in our video table.
47
     */
48
    private static $sites = ['imdb', 'tmdb', 'trakt', 'tvdb', 'tvmaze', 'tvrage'];
49
50
    /**
51
     * @var array Temp Array of cached failed lookups
52
     */
53
    public array $titleCache;
54
55
    public function __construct()
56
    {
57
        $this->echooutput = config('nntmux.echocli');
58
        $this->titleCache = [];
59
    }
60
61
    /**
62
     * Main processing director function for scrapers
63
     * Calls work query function and initiates processing.
64
     */
65
    abstract public function processSite(int $groupID, string $guidChar, int $process, bool $local = false): void;
66
67
    /**
68
     * @return false|mixed
69
     */
70
    public function getSiteIDFromVideoID(string $siteColumn, int $videoID): mixed
71
    {
72
        if (\in_array($siteColumn, self::$sites, false)) {
73
            $result = Video::query()->where('id', $videoID)->first([$siteColumn]);
74
75
            return $result !== null ? $result[$siteColumn] : false;
76
        }
77
78
        return false;
79
    }
80
81
    /**
82
     * Get TV show local timezone from a Video ID.
83
     *
84
     * @return string Empty string if no query return or tz style timezone
85
     */
86
    public function getLocalZoneFromVideoID(int $videoID): string
87
    {
88
        $result = TvInfo::query()->where('videos_id', $videoID)->first(['localzone']);
89
90
        return $result !== null ? $result['localzone'] : '';
91
    }
92
93
    /**
94
     * Get video info from a Site ID and column.
95
     */
96
    protected function getVideoIDFromSiteID(string $siteColumn, int $siteID): bool|int
97
    {
98
        if ($siteID === 0) {
99
            return false;
100
        }
101
102
        $result = false;
103
        if (\in_array($siteColumn, self::$sites, false)) {
104
            $result = Video::query()->where($siteColumn, $siteID)->first();
105
        }
106
        if (! empty($result)) {
107
            $query = $result->toArray();
108
109
            return $query['id'];
110
        }
111
112
        return false;
113
    }
114
115
    public function getByTitle(string $title, int $type, int $source = 0)
116
    {
117
        // Check if we already have an entry for this show.
118
        $res = $this->getTitleExact($title, $type, $source);
119
        if ($res !== 0) {
120
            return $res;
121
        }
122
123
        // If title contains a year in parentheses, try without the year
124
        if (preg_match('/^(.+?)\s*\(\d{4}\)$/', $title, $yearMatch)) {
125
            $titleWithoutYear = trim($yearMatch[1]);
126
            $res = $this->getTitleExact($titleWithoutYear, $type, $source);
127
            if ($res !== 0) {
128
                return $res;
129
            }
130
        }
131
132
        // Check alt. title (Strip ' and :) Maybe strip more in the future.
133
        $res = $this->getAlternativeTitleExact($title, $type, $source);
134
        if ($res !== 0) {
135
            return $res;
136
        }
137
138
        $title2 = str_ireplace(' and ', ' & ', $title);
139
        if ((string) $title !== (string) $title2) {
140
            $res = $this->getTitleExact($title2, $type, $source);
0 ignored issues
show
Bug introduced by
It seems like $title2 can also be of type array; however, parameter $title of App\Services\TvProcessin...ovider::getTitleExact() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
            $res = $this->getTitleExact(/** @scrutinizer ignore-type */ $title2, $type, $source);
Loading history...
141
            if ($res !== 0) {
142
                return $res;
143
            }
144
            $pieces = explode(' ', $title2);
0 ignored issues
show
Bug introduced by
It seems like $title2 can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

144
            $pieces = explode(' ', /** @scrutinizer ignore-type */ $title2);
Loading history...
145
            $title2 = '%';
146
            foreach ($pieces as $piece) {
147
                $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
0 ignored issues
show
Bug introduced by
Are you sure str_ireplace(array(''', '!'), '', $piece) of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

147
                $title2 .= /** @scrutinizer ignore-type */ str_ireplace(["'", '!'], '', $piece).'%';
Loading history...
148
            }
149
            $res = $this->getTitleLoose($title2, $type, $source);
150
            if ($res !== 0) {
151
                return $res;
152
            }
153
        }
154
155
        // Some words are spelled correctly 2 ways
156
        // example theatre and theater
157
        $title2 = str_ireplace('er', 're', $title);
158
        if ((string) $title !== (string) $title2) {
159
            $res = $this->getTitleExact($title2, $type, $source);
160
            if ($res !== 0) {
161
                return $res;
162
            }
163
            $pieces = explode(' ', $title2);
164
            $title2 = '%';
165
            foreach ($pieces as $piece) {
166
                $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
167
            }
168
            $res = $this->getTitleLoose($title2, $type, $source);
169
            if ($res !== 0) {
170
                return $res;
171
            }
172
        } else {
173
            // If there was not an exact title match, look for title with missing chars
174
            // example release name :Zorro 1990, tvrage name Zorro (1990)
175
            // Only search if the title contains more than one word to prevent incorrect matches
176
            $pieces = explode(' ', $title);
177
            if (\count($pieces) > 1) {
178
                $title2 = '%';
179
                foreach ($pieces as $piece) {
180
                    $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
181
                }
182
                $res = $this->getTitleLoose($title2, $type, $source);
183
                if ($res !== 0) {
184
                    return $res;
185
                }
186
            }
187
        }
188
189
        return 0;
190
    }
191
192
    public function getTitleExact(string $title, int $type, int $source = 0): int
193
    {
194
        $return = 0;
195
        if (! empty($title)) {
196
            $sql = Video::query()->where(['title' => $title, 'type' => $type]);
197
            if ($source > 0) {
198
                $sql->where('source', $source);
199
            }
200
            $query = $sql->first();
201
            if (! empty($query)) {
202
                $result = $query->toArray();
203
                $return = $result['id'];
204
            }
205
            // Try for an alias
206
            if (empty($return)) {
207
                $sql = Video::query()
208
                    ->join('videos_aliases', 'videos.id', '=', 'videos_aliases.videos_id')
209
                    ->where(['videos_aliases.title' => $title, 'videos.type' => $type]);
210
                if ($source > 0) {
211
                    $sql->where('videos.source', $source);
212
                }
213
                $query = $sql->first();
214
                if (! empty($query)) {
215
                    $result = $query->toArray();
216
                    $return = $result['id'];
217
                }
218
            }
219
        }
220
221
        return $return;
222
    }
223
224
    /**
225
     * @return int|mixed
226
     */
227
    public function getTitleLoose($title, $type, int $source = 0): mixed
228
    {
229
        $return = 0;
230
231
        if (! empty($title)) {
232
            $sql = Video::query()
233
                ->where('title', 'like', rtrim($title, '%'))
234
                ->where('type', $type);
235
            if ($source > 0) {
236
                $sql->where('source', $source);
237
            }
238
            $query = $sql->first();
239
            if (! empty($query)) {
240
                $result = $query->toArray();
241
                $return = $result['id'];
242
            }
243
            // Try for an alias
244
            if (empty($return)) {
245
                $sql = Video::query()
246
                    ->join('videos_aliases', 'videos.id', '=', 'videos_aliases.videos_id')
247
                    ->where('videos_aliases.title', '=', rtrim($title, '%'))
248
                    ->where('type', $type);
249
                if ($source > 0) {
250
                    $sql->where('videos.source', $source);
251
                }
252
                $query = $sql->first();
253
                if (! empty($query)) {
254
                    $result = $query->toArray();
255
                    $return = $result['id'];
256
                }
257
            }
258
        }
259
260
        return $return;
261
    }
262
263
    /**
264
     * @return int|mixed
265
     */
266
    public function getAlternativeTitleExact(string $title, int $type, int $source = 0): mixed
267
    {
268
        $return = 0;
269
        if (! empty($title)) {
270
            if ($source > 0) {
271
                $query = Video::query()
272
                    ->whereRaw("REPLACE(title,'\'','') = ?", $title)
273
                    ->orWhereRaw("REPLACE(title,':','') = ?", $title)
274
                    ->where('type', '=', $type)
275
                    ->where('source', '=', $source)
276
                    ->first();
277
            } else {
278
                $query = Video::query()
279
                    ->whereRaw("REPLACE(title,'\'','') = ?", $title)
280
                    ->orWhereRaw("REPLACE(title,':','') = ?", $title)
281
                    ->where('type', '=', $type)
282
                    ->first();
283
            }
284
            if (! empty($query)) {
285
                $result = $query->toArray();
286
287
                return $result['id'];
288
            }
289
        }
290
291
        return $return;
292
    }
293
294
    /**
295
     * Inserts aliases for videos.
296
     */
297
    public function addAliases($videoId, array $aliases = []): void
298
    {
299
        if (! empty($aliases) && $videoId > 0) {
300
            foreach ($aliases as $key => $title) {
301
                // Check for tvmaze style aka
302
                if (\is_array($title) && ! empty($title['name'])) {
303
                    $title = $title['name'];
304
                }
305
                // Check if we have the AKA already
306
                $check = $this->getAliases($videoId, $title);
307
308
                if ($check === false) {
309
                    VideoAlias::insertOrIgnore(['videos_id' => $videoId, 'title' => $title, 'created_at' => now(), 'updated_at' => now()]);
310
                }
311
            }
312
        }
313
    }
314
315
    /**
316
     * Retrieves all aliases for given VideoID or VideoID for a given alias.
317
     *
318
     *
319
     * @return VideoAlias[]|bool|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|mixed
320
     */
321
    public function getAliases(int $videoId, string $alias = ''): mixed
322
    {
323
        $return = false;
324
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
325
326
        if ($videoId > 0 || $alias !== '') {
327
            $aliasCache = Cache::get(md5($videoId.$alias));
328
            if ($aliasCache !== null) {
329
                $return = $aliasCache;
330
            } else {
331
                $sql = VideoAlias::query();
332
                if ($videoId > 0) {
333
                    $sql->where('videos_id', $videoId);
334
                } elseif ($alias !== '') {
335
                    $sql->where('title', $alias);
336
                }
337
                $return = $sql->get();
338
                Cache::put(md5($videoId.$alias), $return, $expiresAt);
339
            }
340
        }
341
342
        return $return->isEmpty() ? false : $return;
343
    }
344
}
345
346