flickarr 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/HELP.txt +3 -0
- data/README.md +1 -1
- data/{HOWTO.md → doc/HOWTO.md} +18 -8
- data/doc/how-to-1.png +0 -0
- data/doc/how-to-2.png +0 -0
- data/doc/how-to-3.png +0 -0
- data/doc/how-to-4.png +0 -0
- data/doc/how-to-5.png +0 -0
- data/doc/how-to-6.png +0 -0
- data/lib/flickarr/cli.rb +73 -2
- data/lib/flickarr/collection.rb +4 -2
- data/lib/flickarr/config.rb +36 -29
- data/lib/flickarr/photo_set.rb +4 -2
- data/lib/flickarr/post.rb +16 -2
- data/lib/flickarr/version.rb +65 -1
- metadata +8 -3
- data/TODO.md +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c94bc7b1f3ffc434e88faf5a632728406d6c297e2256354d5053af345be8d649
|
|
4
|
+
data.tar.gz: d2ed214497de643eab92773755bd4b33a655532266736fd4d964d0a3cf1a07a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0060a46d0cb77a92dfaae7a5cc9a21f2979dfa4b7d36d67a3c3bfb2930702e00751f8f9a204455ceb74a55199f7f23f7b93f87e1955889d406326a0a673babb0
|
|
7
|
+
data.tar.gz: 439ae3fbb665d42b07302b34b7d9070ca06e5064d227f998fcf7c8cb5d0a74dd08adf2b9adceec22f7eecb8e7c1cfe274b4baaa431ee0900dcdd1b7efffd7af1
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.1.6] - 2026-03-31
|
|
4
|
+
|
|
5
|
+
- Add `version` and `help` commands to help output
|
|
6
|
+
- Retry transient Flickr API errors ("service not currently available") with backoff, instead of crashing
|
|
7
|
+
- Truncate very long slugs to prevent `Errno::ENAMETOOLONG` on filenames exceeding 255 bytes
|
|
8
|
+
|
|
9
|
+
## [0.1.5] - 2026-03-23
|
|
10
|
+
|
|
11
|
+
- Add `flickarr version` / `-v` / `--version` command
|
|
12
|
+
- Show version header in help output
|
|
13
|
+
- Check for gem updates: always on `version` and `status`, periodically (daily) after other commands
|
|
14
|
+
|
|
3
15
|
## [0.1.4] - 2026-03-22
|
|
4
16
|
|
|
5
17
|
- Retry transient network errors (connection reset, timeouts, HTML-instead-of-JSON) up to 3 times with backoff
|
data/HELP.txt
CHANGED
|
@@ -48,3 +48,6 @@ COMMANDS:
|
|
|
48
48
|
export:collections Export all collections (groups of albums)
|
|
49
49
|
export:collections <URL> Export a single collection (groups of albums) with references to albums
|
|
50
50
|
export:profile Export Flickr profile to archive
|
|
51
|
+
|
|
52
|
+
help, -h, --help Show this help
|
|
53
|
+
version, -v, --version Show version (checks for updates)
|
data/README.md
CHANGED
data/{HOWTO.md → doc/HOWTO.md}
RENAMED
|
@@ -22,16 +22,24 @@ gem install flickarr
|
|
|
22
22
|
|
|
23
23
|
You need your own Flickr API key and secret. Flickarr uses these to authenticate with the Flickr API on your behalf.
|
|
24
24
|
|
|
25
|
-
1. Go to https://
|
|
26
|
-
|
|
25
|
+
1. Go to https://flickr.com/services/apps/create and click the [Request an API Key](https://flickr.com/services/apps/create/apply) link in the **Get your API Key** section.
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
2. On the next page https://flickr.com/services/apps/create/apply click "[Apply for a Non-Commercial Key](https://flickr.com/services/apps/create/noncommercial)"
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
27
32
|
3. Fill in the form:
|
|
28
33
|
- **Application Name**: anything you want (e.g. "Flickarr Export")
|
|
29
34
|
- **Description**: anything (e.g. "Personal archive export")
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
30
38
|
4. Submit the form
|
|
39
|
+
|
|
31
40
|
5. Copy your **Key** and **Secret** from the confirmation page
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
<!-- TODO: screenshot of Flickr API key and secret confirmation page -->
|
|
42
|
+

|
|
35
43
|
|
|
36
44
|
## 4. Initialize Flickarr
|
|
37
45
|
|
|
@@ -73,10 +81,12 @@ This starts the OAuth flow:
|
|
|
73
81
|
2. Flickr asks you to authorize the app — click "OK, I'll Authorize It"
|
|
74
82
|
3. Flickr shows you a verification code (9 digits, like `888-675-309`)
|
|
75
83
|
4. Copy that code
|
|
84
|
+
|
|
85
|
+

|
|
86
|
+
|
|
76
87
|
5. Paste the code back into your terminal
|
|
77
88
|
|
|
78
|
-
|
|
79
|
-
<!-- TODO: screenshot of Flickr verification code page -->
|
|
89
|
+

|
|
80
90
|
|
|
81
91
|
After authenticating, your access tokens, username, and user ID are saved to the config file. You only need to do this once.
|
|
82
92
|
|
|
@@ -134,7 +144,7 @@ flickarr export:albums
|
|
|
134
144
|
Export a single album by URL:
|
|
135
145
|
|
|
136
146
|
```sh
|
|
137
|
-
flickarr export:sets https://
|
|
147
|
+
flickarr export:sets https://flickr.com/photos/USERNAME/sets/72157718538273371/
|
|
138
148
|
```
|
|
139
149
|
|
|
140
150
|
Collections (groups of albums) work the same way:
|
|
@@ -146,7 +156,7 @@ flickarr export:collections
|
|
|
146
156
|
Export a single collection by URL:
|
|
147
157
|
|
|
148
158
|
```sh
|
|
149
|
-
flickarr export:collections https://
|
|
159
|
+
flickarr export:collections https://flickr.com/photos/USERNAME/collections/72157666222057746/
|
|
150
160
|
```
|
|
151
161
|
|
|
152
162
|
## 10. Check your progress
|
data/doc/how-to-1.png
ADDED
|
Binary file
|
data/doc/how-to-2.png
ADDED
|
Binary file
|
data/doc/how-to-3.png
ADDED
|
Binary file
|
data/doc/how-to-4.png
ADDED
|
Binary file
|
data/doc/how-to-5.png
ADDED
|
Binary file
|
data/doc/how-to-6.png
ADDED
|
Binary file
|
data/lib/flickarr/cli.rb
CHANGED
|
@@ -4,7 +4,8 @@ module Flickarr
|
|
|
4
4
|
class CLI
|
|
5
5
|
DEFAULT_CONFIG_PATH = File.join(Dir.home, '.flickarr', 'config.yml').freeze
|
|
6
6
|
VALID_CONFIG_KEYS = %i[access_secret access_token api_key last_page_photos last_page_posts last_page_videos
|
|
7
|
-
library_path shared_secret
|
|
7
|
+
latest_version latest_version_checked_at library_path shared_secret
|
|
8
|
+
total_collections total_photos total_sets total_videos
|
|
8
9
|
user_nsid username].freeze
|
|
9
10
|
|
|
10
11
|
def initialize args, config_path: DEFAULT_CONFIG_PATH
|
|
@@ -12,7 +13,7 @@ module Flickarr
|
|
|
12
13
|
@limit = nil
|
|
13
14
|
@overwrite = false
|
|
14
15
|
|
|
15
|
-
if args.empty? || %w[-h --help help].include?(args.first)
|
|
16
|
+
if args.empty? || %w[-h --help help -v --version version].include?(args.first)
|
|
16
17
|
@args = args
|
|
17
18
|
else
|
|
18
19
|
@parser = build_parser
|
|
@@ -35,12 +36,15 @@ module Flickarr
|
|
|
35
36
|
when 'export:photos' then run_export_posts(media: 'photos')
|
|
36
37
|
when 'export:profile' then run_export_profile
|
|
37
38
|
when 'export:videos' then run_export_posts(media: 'videos')
|
|
39
|
+
when '-v', '--version', 'version' then run_version
|
|
38
40
|
when 'init' then run_init
|
|
39
41
|
when 'open' then run_open
|
|
40
42
|
when 'path' then run_path
|
|
41
43
|
when 'status' then run_status
|
|
42
44
|
else print_help
|
|
43
45
|
end
|
|
46
|
+
|
|
47
|
+
check_for_update unless %w[-v --version version status -h --help help config config:set init].include?(command)
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
private
|
|
@@ -301,7 +305,13 @@ module Flickarr
|
|
|
301
305
|
collection_count = count_subdirs(File.join(archive, 'Collections'))
|
|
302
306
|
disk_usage = human_size(dir_size(archive))
|
|
303
307
|
|
|
308
|
+
checker = Version.new(config)
|
|
309
|
+
checker.check
|
|
310
|
+
config.save(@config_path)
|
|
311
|
+
version_str = checker.update_message || "#{Flickarr::VERSION} (up to date)"
|
|
312
|
+
|
|
304
313
|
rows = [
|
|
314
|
+
['Version', version_str],
|
|
305
315
|
['Archive', archive],
|
|
306
316
|
['Profile', profile_exists ? 'Downloaded' : 'Not downloaded'],
|
|
307
317
|
['Photos', format_count(photo_count, config.total_photos)],
|
|
@@ -353,6 +363,35 @@ module Flickarr
|
|
|
353
363
|
end
|
|
354
364
|
end
|
|
355
365
|
|
|
366
|
+
def check_for_update
|
|
367
|
+
return unless File.exist?(@config_path)
|
|
368
|
+
|
|
369
|
+
config = Config.load(@config_path)
|
|
370
|
+
checker = Version.new(config)
|
|
371
|
+
return unless checker.stale?
|
|
372
|
+
|
|
373
|
+
message = checker.update_message
|
|
374
|
+
config.save(@config_path)
|
|
375
|
+
return unless message
|
|
376
|
+
|
|
377
|
+
warn "\n#{message}"
|
|
378
|
+
rescue StandardError
|
|
379
|
+
nil
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def run_version
|
|
383
|
+
config = Config.load(@config_path)
|
|
384
|
+
checker = Version.new(config)
|
|
385
|
+
latest = checker.check
|
|
386
|
+
config.save(@config_path)
|
|
387
|
+
|
|
388
|
+
if latest && Gem::Version.new(latest) > Gem::Version.new(Flickarr::VERSION)
|
|
389
|
+
puts "#{Flickarr::VERSION} (latest: #{latest} — run `gem update flickarr`)"
|
|
390
|
+
else
|
|
391
|
+
puts "#{Flickarr::VERSION} (up to date)"
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
356
395
|
def count_subdirs path
|
|
357
396
|
return 0 unless Dir.exist?(path)
|
|
358
397
|
|
|
@@ -471,6 +510,18 @@ module Flickarr
|
|
|
471
510
|
end
|
|
472
511
|
warn "Failed to fetch page #{page} after retries: #{e.message}"
|
|
473
512
|
break
|
|
513
|
+
rescue Flickr::FailedResponse => e
|
|
514
|
+
if transient_flickr_error?(e)
|
|
515
|
+
page_retries -= 1
|
|
516
|
+
if page_retries.positive?
|
|
517
|
+
warn "Transient API error fetching page #{page}: #{e.message} — retrying in 5s (#{page_retries} left)"
|
|
518
|
+
sleep 5
|
|
519
|
+
retry
|
|
520
|
+
end
|
|
521
|
+
warn "Failed to fetch page #{page} after retries: #{e.message}"
|
|
522
|
+
break
|
|
523
|
+
end
|
|
524
|
+
raise
|
|
474
525
|
end
|
|
475
526
|
total = response.total.to_i
|
|
476
527
|
total_pages = response.pages.to_i
|
|
@@ -561,6 +612,17 @@ module Flickarr
|
|
|
561
612
|
log_error archive: archive, post_id: post_id, username: config.username, error: e
|
|
562
613
|
return
|
|
563
614
|
rescue Flickr::FailedResponse => e
|
|
615
|
+
if transient_flickr_error?(e)
|
|
616
|
+
retries -= 1
|
|
617
|
+
if retries.positive?
|
|
618
|
+
warn "Transient API error on post #{post_id}: #{e.message} — retrying in 5s (#{retries} left)"
|
|
619
|
+
sleep 5
|
|
620
|
+
retry
|
|
621
|
+
end
|
|
622
|
+
warn "Failed post #{post_id} after retries: #{e.message}"
|
|
623
|
+
log_error archive: archive, post_id: post_id, username: config.username, error: e
|
|
624
|
+
return
|
|
625
|
+
end
|
|
564
626
|
warn "Error on post #{post_id}: #{e.message}"
|
|
565
627
|
log_error archive: archive, post_id: post_id, username: config.username, error: e
|
|
566
628
|
return
|
|
@@ -579,6 +641,13 @@ module Flickarr
|
|
|
579
641
|
end
|
|
580
642
|
end
|
|
581
643
|
|
|
644
|
+
def transient_flickr_error? error
|
|
645
|
+
message = error.message.to_s.downcase
|
|
646
|
+
code = error.respond_to?(:code) ? error.code.to_s : ''
|
|
647
|
+
|
|
648
|
+
code == '105' || message.include?('not currently available') || message.include?('service unavailable')
|
|
649
|
+
end
|
|
650
|
+
|
|
582
651
|
def log_error archive:, post_id:, username:, error:
|
|
583
652
|
log_path = File.join archive, '_errors.log'
|
|
584
653
|
FileUtils.mkdir_p File.dirname(log_path)
|
|
@@ -707,6 +776,8 @@ module Flickarr
|
|
|
707
776
|
end
|
|
708
777
|
|
|
709
778
|
def print_help
|
|
779
|
+
puts "flickarr version #{Flickarr::VERSION}"
|
|
780
|
+
puts
|
|
710
781
|
help_path = File.expand_path('../../HELP.txt', __dir__)
|
|
711
782
|
puts File.read(help_path)
|
|
712
783
|
puts
|
data/lib/flickarr/collection.rb
CHANGED
|
@@ -28,13 +28,15 @@ module Flickarr
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def dirname
|
|
31
|
-
|
|
31
|
+
truncated = Post.truncate_slug(slug, id: id, ext: '')
|
|
32
|
+
[id, truncated].compact.join '_'
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def sets_to_a
|
|
35
36
|
@set_refs.map do |s|
|
|
36
37
|
set_slug = s.title.to_s.slugify
|
|
37
|
-
|
|
38
|
+
set_slug = Post.truncate_slug(set_slug, id: s.id, ext: '')
|
|
39
|
+
set_dirname = [s.id, set_slug].compact.join('_')
|
|
38
40
|
|
|
39
41
|
{
|
|
40
42
|
description: s.description.to_s,
|
data/lib/flickarr/config.rb
CHANGED
|
@@ -6,7 +6,8 @@ module Flickarr
|
|
|
6
6
|
DEFAULT_LIBRARY_PATH = File.join(Dir.home, 'Pictures', 'Flickarr').freeze
|
|
7
7
|
|
|
8
8
|
attr_accessor :access_secret, :access_token, :api_key, :last_page_photos, :last_page_posts, :last_page_videos,
|
|
9
|
-
:
|
|
9
|
+
:latest_version, :latest_version_checked_at, :library_path, :shared_secret,
|
|
10
|
+
:total_collections, :total_photos, :total_sets, :total_videos,
|
|
10
11
|
:user_nsid, :username
|
|
11
12
|
|
|
12
13
|
def initialize
|
|
@@ -16,6 +17,8 @@ module Flickarr
|
|
|
16
17
|
@last_page_photos = nil
|
|
17
18
|
@last_page_posts = nil
|
|
18
19
|
@last_page_videos = nil
|
|
20
|
+
@latest_version = nil
|
|
21
|
+
@latest_version_checked_at = nil
|
|
19
22
|
@library_path = DEFAULT_LIBRARY_PATH
|
|
20
23
|
@shared_secret = ENV.fetch('FLICKARR_SHARED_SECRET', nil)
|
|
21
24
|
@total_collections = nil
|
|
@@ -43,20 +46,22 @@ module Flickarr
|
|
|
43
46
|
|
|
44
47
|
def to_h
|
|
45
48
|
{
|
|
46
|
-
access_secret:
|
|
47
|
-
access_token:
|
|
48
|
-
api_key:
|
|
49
|
-
last_page_photos:
|
|
50
|
-
last_page_posts:
|
|
51
|
-
last_page_videos:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
access_secret: access_secret,
|
|
50
|
+
access_token: access_token,
|
|
51
|
+
api_key: api_key,
|
|
52
|
+
last_page_photos: last_page_photos,
|
|
53
|
+
last_page_posts: last_page_posts,
|
|
54
|
+
last_page_videos: last_page_videos,
|
|
55
|
+
latest_version: latest_version,
|
|
56
|
+
latest_version_checked_at: latest_version_checked_at,
|
|
57
|
+
library_path: library_path,
|
|
58
|
+
shared_secret: shared_secret,
|
|
59
|
+
total_collections: total_collections,
|
|
60
|
+
total_photos: total_photos,
|
|
61
|
+
total_sets: total_sets,
|
|
62
|
+
total_videos: total_videos,
|
|
63
|
+
user_nsid: user_nsid,
|
|
64
|
+
username: username
|
|
60
65
|
}
|
|
61
66
|
end
|
|
62
67
|
|
|
@@ -67,20 +72,22 @@ module Flickarr
|
|
|
67
72
|
yaml = YAML.load_file(path, symbolize_names: true)
|
|
68
73
|
return config unless yaml.is_a?(Hash)
|
|
69
74
|
|
|
70
|
-
config.access_secret
|
|
71
|
-
config.access_token
|
|
72
|
-
config.api_key
|
|
73
|
-
config.last_page_photos
|
|
74
|
-
config.last_page_posts
|
|
75
|
-
config.last_page_videos
|
|
76
|
-
config.
|
|
77
|
-
config.
|
|
78
|
-
config.
|
|
79
|
-
config.
|
|
80
|
-
config.
|
|
81
|
-
config.
|
|
82
|
-
config.
|
|
83
|
-
config.
|
|
75
|
+
config.access_secret = yaml[:access_secret] if yaml[:access_secret]
|
|
76
|
+
config.access_token = yaml[:access_token] if yaml[:access_token]
|
|
77
|
+
config.api_key = yaml[:api_key] if yaml[:api_key]
|
|
78
|
+
config.last_page_photos = yaml[:last_page_photos] if yaml[:last_page_photos]
|
|
79
|
+
config.last_page_posts = yaml[:last_page_posts] if yaml[:last_page_posts]
|
|
80
|
+
config.last_page_videos = yaml[:last_page_videos] if yaml[:last_page_videos]
|
|
81
|
+
config.latest_version = yaml[:latest_version] if yaml[:latest_version]
|
|
82
|
+
config.latest_version_checked_at = yaml[:latest_version_checked_at] if yaml[:latest_version_checked_at]
|
|
83
|
+
config.library_path = yaml[:library_path] if yaml[:library_path]
|
|
84
|
+
config.shared_secret = yaml[:shared_secret] if yaml[:shared_secret]
|
|
85
|
+
config.total_collections = yaml[:total_collections] if yaml[:total_collections]
|
|
86
|
+
config.total_photos = yaml[:total_photos] if yaml[:total_photos]
|
|
87
|
+
config.total_sets = yaml[:total_sets] if yaml[:total_sets]
|
|
88
|
+
config.total_videos = yaml[:total_videos] if yaml[:total_videos]
|
|
89
|
+
config.user_nsid = yaml[:user_nsid] if yaml[:user_nsid]
|
|
90
|
+
config.username = yaml[:username] if yaml[:username]
|
|
84
91
|
|
|
85
92
|
config
|
|
86
93
|
end
|
data/lib/flickarr/photo_set.rb
CHANGED
|
@@ -42,7 +42,8 @@ module Flickarr
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def dirname
|
|
45
|
-
|
|
45
|
+
truncated = Post.truncate_slug(slug, id: id, ext: '')
|
|
46
|
+
[id, truncated].compact.join '_'
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
def photos_to_a
|
|
@@ -110,7 +111,8 @@ module Flickarr
|
|
|
110
111
|
def relative_photo_path item
|
|
111
112
|
ext = item.media.to_s == 'video' ? 'mp4' : item.originalformat.to_s
|
|
112
113
|
slug = item.title.to_s.slugify
|
|
113
|
-
|
|
114
|
+
slug = Post.truncate_slug(slug, id: item.id, ext: ext)
|
|
115
|
+
base = [item.id, slug].compact.join('_')
|
|
114
116
|
date = if item.datetakenunknown.to_i.zero?
|
|
115
117
|
Date.parse item.datetaken
|
|
116
118
|
else
|
data/lib/flickarr/post.rb
CHANGED
|
@@ -8,6 +8,7 @@ require 'yaml'
|
|
|
8
8
|
module Flickarr
|
|
9
9
|
class Post
|
|
10
10
|
FLICKR_URL_PATTERN = %r{\Ahttps?://(?:www\.)?flickr\.com/photos/[^/]+/(\d+)}
|
|
11
|
+
MAX_FILENAME_BYTES = 255
|
|
11
12
|
|
|
12
13
|
def self.build info:, sizes:, exif: nil
|
|
13
14
|
case info.media.to_s
|
|
@@ -25,14 +26,25 @@ module Flickarr
|
|
|
25
26
|
id = item.id
|
|
26
27
|
title = item.title.to_s
|
|
27
28
|
slug = title.slugify
|
|
28
|
-
basename = [id, slug.empty? ? nil : slug].compact.join('_')
|
|
29
29
|
ext = item.media.to_s == 'video' ? 'mp4' : item.originalformat.to_s
|
|
30
|
+
slug = truncate_slug(slug, id: id, ext: ext)
|
|
31
|
+
basename = [id, slug].compact.join('_')
|
|
30
32
|
date = compute_date_from_list_item(item)
|
|
31
33
|
folder = date.strftime '%Y/%m/%d'
|
|
32
34
|
|
|
33
35
|
File.join archive_path, folder, "#{basename}.#{ext}"
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
def self.truncate_slug slug, id:, ext:
|
|
39
|
+
return nil if slug.nil? || slug.empty?
|
|
40
|
+
|
|
41
|
+
# "id_slug.ext" must fit in MAX_FILENAME_BYTES
|
|
42
|
+
max_slug = MAX_FILENAME_BYTES - id.to_s.bytesize - ext.to_s.bytesize - 2 # underscore + dot
|
|
43
|
+
return slug if slug.bytesize <= max_slug
|
|
44
|
+
|
|
45
|
+
slug[0, max_slug].chomp('-')
|
|
46
|
+
end
|
|
47
|
+
|
|
36
48
|
def self.compute_date_from_list_item item
|
|
37
49
|
if item.datetakenunknown.to_i.zero?
|
|
38
50
|
Date.parse item.datetaken
|
|
@@ -75,7 +87,9 @@ module Flickarr
|
|
|
75
87
|
end
|
|
76
88
|
|
|
77
89
|
def basename
|
|
78
|
-
[
|
|
90
|
+
longest_ext = [extension, 'yaml'].max_by(&:bytesize)
|
|
91
|
+
truncated = self.class.truncate_slug(slug, id: id, ext: longest_ext)
|
|
92
|
+
[id, truncated].compact.join '_'
|
|
79
93
|
end
|
|
80
94
|
|
|
81
95
|
def date_taken
|
data/lib/flickarr/version.rb
CHANGED
|
@@ -1,3 +1,67 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
1
5
|
module Flickarr
|
|
2
|
-
VERSION = '0.1.
|
|
6
|
+
VERSION = '0.1.6'.freeze
|
|
7
|
+
|
|
8
|
+
class Version
|
|
9
|
+
RUBYGEMS_URL = 'https://rubygems.org/api/v1/gems/flickarr.json'.freeze
|
|
10
|
+
CACHE_TTL_SECONDS = 86_400 # 1 day
|
|
11
|
+
|
|
12
|
+
def initialize config
|
|
13
|
+
@config = config
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def check
|
|
17
|
+
fetch_latest if stale?
|
|
18
|
+
@config.latest_version
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def stale?
|
|
22
|
+
return true if @config.latest_version_checked_at.nil?
|
|
23
|
+
|
|
24
|
+
last_check = Time.parse(@config.latest_version_checked_at.to_s)
|
|
25
|
+
Time.now - last_check > CACHE_TTL_SECONDS
|
|
26
|
+
rescue ArgumentError
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def update_available?
|
|
31
|
+
latest = check
|
|
32
|
+
return false unless latest
|
|
33
|
+
|
|
34
|
+
Gem::Version.new(latest) > Gem::Version.new(Flickarr::VERSION)
|
|
35
|
+
rescue ArgumentError
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def update_message
|
|
40
|
+
latest = check
|
|
41
|
+
return nil unless latest
|
|
42
|
+
|
|
43
|
+
if Gem::Version.new(latest) > Gem::Version.new(Flickarr::VERSION)
|
|
44
|
+
"Update available: #{latest} (current: #{Flickarr::VERSION}) — run `gem update flickarr`"
|
|
45
|
+
end
|
|
46
|
+
rescue ArgumentError
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def fetch_latest
|
|
53
|
+
uri = URI(RUBYGEMS_URL)
|
|
54
|
+
response = Net::HTTP.get_response(uri)
|
|
55
|
+
return unless response.is_a?(Net::HTTPSuccess)
|
|
56
|
+
|
|
57
|
+
data = JSON.parse(response.body)
|
|
58
|
+
version = data['version']
|
|
59
|
+
|
|
60
|
+
@config.latest_version = version
|
|
61
|
+
@config.latest_version_checked_at = Time.now.iso8601
|
|
62
|
+
version
|
|
63
|
+
rescue StandardError
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
end
|
|
3
67
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: flickarr
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shane Becker
|
|
@@ -91,11 +91,16 @@ files:
|
|
|
91
91
|
- CHANGELOG.md
|
|
92
92
|
- CODE_OF_CONDUCT.md
|
|
93
93
|
- HELP.txt
|
|
94
|
-
- HOWTO.md
|
|
95
94
|
- LICENSE.txt
|
|
96
95
|
- README.md
|
|
97
96
|
- Rakefile
|
|
98
|
-
-
|
|
97
|
+
- doc/HOWTO.md
|
|
98
|
+
- doc/how-to-1.png
|
|
99
|
+
- doc/how-to-2.png
|
|
100
|
+
- doc/how-to-3.png
|
|
101
|
+
- doc/how-to-4.png
|
|
102
|
+
- doc/how-to-5.png
|
|
103
|
+
- doc/how-to-6.png
|
|
99
104
|
- exe/flickarr
|
|
100
105
|
- lib/flickarr.rb
|
|
101
106
|
- lib/flickarr/auth.rb
|