VLCNetworkServerBrowserPlex.m 7.5 KB
Newer Older
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
/*****************************************************************************
 * VLCNetworkServerBrowserPlex.m
 * VLC for iOS
 *****************************************************************************
 * Copyright (c) 2015 VideoLAN. All rights reserved.
 * $Id$
 *
 * Authors: Tobias Conradi <videolan # tobias-conradi.de>
 *
 * Refer to the COPYING file of the official project for license.
 *****************************************************************************/

#import "VLCNetworkServerBrowserPlex.h"
#import "VLCPlexParser.h"
#import "VLCPlexWebAPI.h"

@interface VLCNetworkServerBrowserPlex ()
@property (nonatomic, readonly) NSString *addressOrName;
@property (nonatomic, readonly) NSUInteger port;

@property (nonatomic, readwrite) NSString *title;
@property (nonatomic, readonly) NSString *plexServerAddress;
@property (nonatomic, readonly) NSNumber *plexServerPort;
@property (nonatomic, readonly) NSString *plexServerPath;

@property (nonatomic) NSString *plexAuthentification;

@property (nonatomic, readonly) VLCPlexParser *plexParser;
@property (nonatomic, readonly) VLCPlexWebAPI *plexWebAPI;

@property (nonatomic, readonly) NSOperationQueue *plexQueue;

@property (nonatomic, readwrite) NSArray<id<VLCNetworkServerBrowserItem>> *items;
@end

@implementation VLCNetworkServerBrowserPlex
37
@synthesize title = _title, delegate = _delegate, items = _items, mediaList = _mediaList;
38

39
40
41
42
43
44
45
46
47
- (instancetype)initWithLogin:(VLCNetworkServerLoginInformation *)login
{
    return [self initWithName:login.address
                         host:login.address
                   portNumber:login.port
                         path:@""
           authentificication:@""];
}

48
49
50
51
52
53
- (instancetype)initWithName:(NSString *)name host:(NSString *)addressOrName portNumber:(NSNumber *)portNumber path:(NSString *)path authentificication:(NSString *)auth
{
    self = [super init];
    if (self) {
        _title = name;
        _plexServerAddress = addressOrName;
54
        _plexServerPort = portNumber.intValue > 0 ? portNumber : @(32400);
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
        _plexServerPath = path;

        _plexAuthentification = auth;

        _plexParser = [[VLCPlexParser alloc] init];
        _plexWebAPI = [[VLCPlexWebAPI alloc] init];

        _plexQueue = [[NSOperationQueue alloc] init];
        _plexQueue.maxConcurrentOperationCount = 1;
        _plexQueue.name = @"org.videolan.vlc-ios.plex.update";

        _items = [NSArray new];

    }
    return self;
}

- (instancetype)initWithName:(NSString *)name url:(NSURL *)url auth:(NSString *)auth {
    return [self initWithName:name host:url.host portNumber:url.port path:url.path authentificication:auth];
}

- (void)update {
    [self.plexQueue addOperationWithBlock:^{
        [self loadContents];
    }];
}

- (void)loadContents
{
Tobias's avatar
Tobias committed
84
85
86
87
88
89
90
91
92
    NSError *error = nil;
    NSArray *dicts = [self.plexParser PlexMediaServerParser:self.plexServerAddress port:self.plexServerPort navigationPath:self.plexServerPath authentification:self.plexAuthentification error:&error];

    if (error) {
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self.delegate networkServerBrowser:self requestDidFailWithError:error];
        }];
        return;
    }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

    NSDictionary *firstObject = [dicts firstObject];
    NSString *newAuth = firstObject[@"authentification"] ?: @"";

    NSURLComponents *components = [[NSURLComponents alloc] init];
    components.scheme = @"http";
    components.host = self.plexServerAddress;
    components.port = self.plexServerPort;
    components.path = self.plexServerPath;
    NSURL *url = components.URL;

    NSMutableArray *newItems = [NSMutableArray new];
    for (NSDictionary *dict in dicts) {
        VLCNetworkServerBrowserItemPlex *item = [[VLCNetworkServerBrowserItemPlex alloc] initWithDictionary:dict currentURL:url authentificication:newAuth];
        [newItems addObject:item];
    }

    NSString *titleValue = firstObject[@"libTitle"];
    if (titleValue.length) {
        self.title = titleValue;
    }
    self.plexAuthentification = newAuth;
115
116
117
    @synchronized(_items) {
        _items = [newItems copy];
    }
118
    _mediaList = [self buildMediaList];
119
120
121
122
123
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [self.delegate networkServerBrowserDidUpdate:self];
    }];
}

124
- (VLCMediaList *)buildMediaList
125
{
Pierre SAGASPE's avatar
Pierre SAGASPE committed
126
    NSMutableArray *mediaArray;
127
    @synchronized(_items) {
128
129
130
        mediaArray = [NSMutableArray new];
        for (id<VLCNetworkServerBrowserItem> browseritem in _items) {
            VLCMedia *media = [browseritem media];
131
            if (media)
Pierre SAGASPE's avatar
Pierre SAGASPE committed
132
                [mediaArray addObject:media];
133
134
        }
    }
Pierre SAGASPE's avatar
Pierre SAGASPE committed
135
    VLCMediaList *mediaList = [[VLCMediaList alloc] initWithArray:mediaArray];
136
    return mediaList;
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

- (NSString *)_urlAuth:(NSString *)url
{
    return [self.plexWebAPI urlAuth:url authentification:self.plexAuthentification];
}
@end


@interface VLCNetworkServerBrowserItemPlex()

@property (nonatomic) NSString *plexAuthentification;
@end
@implementation VLCNetworkServerBrowserItemPlex
@synthesize name = _name, URL = _URL, fileSizeBytes = _fileSizeBytes, container = _container;

- (instancetype)initWithDictionary:(NSDictionary *)dictionary currentURL:(NSURL *)currentURL authentificication:(NSString *)auth
{
    self = [super init];
    if (self) {

        _plexAuthentification = auth;
        
        NSURLComponents *components = [[NSURLComponents alloc] initWithURL:currentURL resolvingAgainstBaseURL:NO];

        NSString *path = components.path;
        components.path = nil;
        NSURL *baseURL = components.URL;

        _container = ![dictionary[@"container"] isEqualToString:@"item"];
        NSString *urlPath;
        if (_container) {
            NSString *keyPath = nil;
            NSString *keyValue = dictionary[@"key"];
            if ([keyValue rangeOfString:@"library"].location == NSNotFound) {
                keyPath = [path stringByAppendingPathComponent:keyValue];
            } else {
                keyPath = keyValue;
            }
Tobias's avatar
Tobias committed
176
177
178
            if (keyPath) {
                urlPath = [baseURL URLByAppendingPathComponent:keyPath].absoluteString;
            }
179
180
181
182
183
184
185
186
187
188
189
190
        } else {
            urlPath = dictionary[@"keyMedia"];
        }

        urlPath = [VLCPlexWebAPI urlAuth:urlPath authentification:auth];
        _URL = [NSURL URLWithString:urlPath];

        _name = dictionary[@"title"];
        NSString *thumbPath = dictionary[@"thumb"];
        if (thumbPath) {
            thumbPath = [VLCPlexWebAPI urlAuth:thumbPath authentification:auth];
        }
Tobias's avatar
Tobias committed
191
        _thumbnailURL = thumbPath.length ? [NSURL URLWithString:thumbPath] : nil;
192
193
194

        _duration = dictionary[@"duration"];
        _fileSizeBytes = dictionary[@"size"];
195
        _filename = dictionary[@"namefile"];
196
197
198
199
200
201
202
203
204
205
206

        NSString *subtitleURLString = dictionary[@"keySubtitle"];
        if (subtitleURLString) {
            subtitleURLString = [VLCPlexWebAPI urlAuth:subtitleURLString authentification:auth];
        }

        _subtitleURL = subtitleURLString.length ? [baseURL URLByAppendingPathComponent:subtitleURLString] : nil;
    }
    return self;
}

207
208
209
210
211
212
- (BOOL)isDownloadable
{
    //VLC also needs an extension in the filename for this to work.
    return YES;
}

213
214
215
- (VLCMedia *)media
{
    if (!_URL)
216
        return [VLCMedia mediaAsNodeWithName:self.name];
217

218
219
220
221
222
223
    VLCMedia *media =  [VLCMedia mediaWithURL:_URL];
    NSString *title = self.name;
    if (title.length) {
        [media setMetadata:self.name forKey:VLCMetaInformationTitle];
    }
    return media;
224
225
}

226
227
228
229
230
- (id<VLCNetworkServerBrowser>)containerBrowser {
    return [[VLCNetworkServerBrowserPlex alloc] initWithName:self.name url:self.URL auth:self.plexAuthentification];
}

@end