hiiro 0.1.81 → 0.1.82
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/bin/h-pr +115 -8
- data/lib/hiiro/version.rb +1 -1
- metadata +1 -8
- data/bin/h-home +0 -62
- data/bin/h-html +0 -380
- data/bin/h-mic +0 -93
- data/bin/h-note +0 -119
- data/bin/h-remind +0 -614
- data/bin/h-serve +0 -6
- data/bin/h-video +0 -523
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 31fd73a56f9bbcc10a8a9e62ecdd0dcbc391eb65e0bcf5886ab289986f81a198
|
|
4
|
+
data.tar.gz: dd392dc066b2ec7c894a2d7c2d14c8d2921f157a4b998dde9ee7ffdb83400844
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 705c6f8c3aa58a2f356272a647d67fb84a7b7c6c39b271c2372e4b3498a0d644415a75d2fad9ff16c80a73949fdc432052e6ef7d00e97149c412eb290c1fb13a
|
|
7
|
+
data.tar.gz: df6abb83f94c9433a992f359d66393c8c3c9db28c5d920d32529bf58a3fe536114da0396298fdf4400b062058acb054e57dc83696d5d5ada96a9319ef8ee5e86
|
data/bin/h-pr
CHANGED
|
@@ -295,7 +295,7 @@ class PinnedPRManager
|
|
|
295
295
|
end
|
|
296
296
|
|
|
297
297
|
def fetch_pr_info(pr_number)
|
|
298
|
-
fields = 'number,title,url,headRefName,state,statusCheckRollup'
|
|
298
|
+
fields = 'number,title,url,headRefName,state,statusCheckRollup,reviewDecision,reviews,isDraft,mergeable'
|
|
299
299
|
output = `gh pr view #{pr_number} --json #{fields} 2>/dev/null`.strip
|
|
300
300
|
return nil if output.empty?
|
|
301
301
|
JSON.parse(output)
|
|
@@ -325,6 +325,10 @@ class PinnedPRManager
|
|
|
325
325
|
pr['state'] = info['state']
|
|
326
326
|
pr['title'] = info['title']
|
|
327
327
|
pr['checks'] = summarize_checks(info['statusCheckRollup'])
|
|
328
|
+
pr['reviews'] = summarize_reviews(info['reviews'])
|
|
329
|
+
pr['review_decision'] = info['reviewDecision']
|
|
330
|
+
pr['is_draft'] = info['isDraft']
|
|
331
|
+
pr['mergeable'] = info['mergeable']
|
|
328
332
|
pr['last_checked'] = Time.now.iso8601
|
|
329
333
|
pr
|
|
330
334
|
end
|
|
@@ -343,28 +347,124 @@ class PinnedPRManager
|
|
|
343
347
|
{ 'total' => total, 'success' => success, 'pending' => pending, 'failed' => failed }
|
|
344
348
|
end
|
|
345
349
|
|
|
350
|
+
def summarize_reviews(reviews)
|
|
351
|
+
return nil unless reviews.is_a?(Array) && !reviews.empty?
|
|
352
|
+
|
|
353
|
+
# Get the latest review state per author
|
|
354
|
+
latest_by_author = {}
|
|
355
|
+
reviews.each do |review|
|
|
356
|
+
author = review['author']['login'] rescue nil
|
|
357
|
+
next unless author
|
|
358
|
+
# Only track if it's a meaningful state
|
|
359
|
+
state = review['state']
|
|
360
|
+
next unless %w[APPROVED CHANGES_REQUESTED COMMENTED].include?(state)
|
|
361
|
+
latest_by_author[author] = state
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
approved = latest_by_author.values.count { |s| s == 'APPROVED' }
|
|
365
|
+
changes_requested = latest_by_author.values.count { |s| s == 'CHANGES_REQUESTED' }
|
|
366
|
+
commented = latest_by_author.values.count { |s| s == 'COMMENTED' }
|
|
367
|
+
|
|
368
|
+
{ 'approved' => approved, 'changes_requested' => changes_requested, 'commented' => commented, 'reviewers' => latest_by_author }
|
|
369
|
+
end
|
|
370
|
+
|
|
346
371
|
def display_pinned(pr, idx = nil)
|
|
347
372
|
num = idx ? "#{(idx + 1).to_s.rjust(3)}." : ""
|
|
348
373
|
state_icon = case pr['state']
|
|
349
374
|
when 'MERGED' then '[M]'
|
|
350
375
|
when 'CLOSED' then '[X]'
|
|
351
|
-
else '[O]'
|
|
376
|
+
else pr['is_draft'] ? '[D]' : '[O]'
|
|
352
377
|
end
|
|
353
378
|
|
|
354
379
|
checks_str = if pr['checks']
|
|
355
380
|
c = pr['checks']
|
|
356
381
|
if c['failed'] > 0
|
|
357
|
-
"
|
|
382
|
+
" checks:#{c['success']}/#{c['total']} FAIL:#{c['failed']}"
|
|
358
383
|
elsif c['pending'] > 0
|
|
359
|
-
"
|
|
384
|
+
" checks:#{c['success']}/#{c['total']} pending:#{c['pending']}"
|
|
360
385
|
else
|
|
361
|
-
"
|
|
386
|
+
" checks:#{c['success']}/#{c['total']}"
|
|
362
387
|
end
|
|
363
388
|
else
|
|
364
389
|
""
|
|
365
390
|
end
|
|
366
391
|
|
|
367
|
-
|
|
392
|
+
reviews_str = if pr['reviews']
|
|
393
|
+
r = pr['reviews']
|
|
394
|
+
parts = []
|
|
395
|
+
parts << "#{r['approved']} approved" if r['approved'] > 0
|
|
396
|
+
parts << "#{r['changes_requested']} changes" if r['changes_requested'] > 0
|
|
397
|
+
parts.empty? ? "" : " | #{parts.join(', ')}"
|
|
398
|
+
else
|
|
399
|
+
""
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
"#{num} #{state_icon} ##{pr['number']} #{pr['title']}#{checks_str}#{reviews_str}".strip
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def display_detailed(pr, idx = nil)
|
|
406
|
+
lines = []
|
|
407
|
+
num = idx ? "#{idx + 1}." : ""
|
|
408
|
+
|
|
409
|
+
state_str = case pr['state']
|
|
410
|
+
when 'MERGED' then 'MERGED'
|
|
411
|
+
when 'CLOSED' then 'CLOSED'
|
|
412
|
+
else pr['is_draft'] ? 'DRAFT' : 'OPEN'
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
lines << "#{num} ##{pr['number']} - #{pr['title']}"
|
|
416
|
+
lines << " State: #{state_str}"
|
|
417
|
+
lines << " Branch: #{pr['headRefName']}" if pr['headRefName']
|
|
418
|
+
lines << " URL: #{pr['url']}" if pr['url']
|
|
419
|
+
|
|
420
|
+
# Checks
|
|
421
|
+
if pr['checks']
|
|
422
|
+
c = pr['checks']
|
|
423
|
+
check_status = if c['failed'] > 0
|
|
424
|
+
"FAILING (#{c['success']}/#{c['total']} passed, #{c['failed']} failed)"
|
|
425
|
+
elsif c['pending'] > 0
|
|
426
|
+
"PENDING (#{c['success']}/#{c['total']} passed, #{c['pending']} pending)"
|
|
427
|
+
else
|
|
428
|
+
"PASSING (#{c['success']}/#{c['total']})"
|
|
429
|
+
end
|
|
430
|
+
lines << " Checks: #{check_status}"
|
|
431
|
+
else
|
|
432
|
+
lines << " Checks: (none)"
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# Reviews
|
|
436
|
+
if pr['reviews']
|
|
437
|
+
r = pr['reviews']
|
|
438
|
+
review_parts = []
|
|
439
|
+
review_parts << "#{r['approved']} approved" if r['approved'] > 0
|
|
440
|
+
review_parts << "#{r['changes_requested']} requesting changes" if r['changes_requested'] > 0
|
|
441
|
+
review_parts << "#{r['commented']} commented" if r['commented'] > 0
|
|
442
|
+
|
|
443
|
+
if review_parts.any?
|
|
444
|
+
lines << " Reviews: #{review_parts.join(', ')}"
|
|
445
|
+
if r['reviewers'] && !r['reviewers'].empty?
|
|
446
|
+
r['reviewers'].each do |author, state|
|
|
447
|
+
icon = case state
|
|
448
|
+
when 'APPROVED' then '+'
|
|
449
|
+
when 'CHANGES_REQUESTED' then '-'
|
|
450
|
+
else '?'
|
|
451
|
+
end
|
|
452
|
+
lines << " #{icon} #{author}: #{state.downcase.gsub('_', ' ')}"
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
else
|
|
456
|
+
lines << " Reviews: (none)"
|
|
457
|
+
end
|
|
458
|
+
else
|
|
459
|
+
lines << " Reviews: (not fetched)"
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# Mergeable
|
|
463
|
+
if pr['mergeable']
|
|
464
|
+
lines << " Mergeable: #{pr['mergeable']}"
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
lines.join("\n")
|
|
368
468
|
end
|
|
369
469
|
end
|
|
370
470
|
|
|
@@ -586,16 +686,23 @@ hiiro.add_subcmd(:status) do |*args|
|
|
|
586
686
|
next
|
|
587
687
|
end
|
|
588
688
|
|
|
689
|
+
compact = args.include?('-c') || args.include?('--compact')
|
|
690
|
+
|
|
589
691
|
puts "Refreshing status for #{pinned.length} pinned PR(s)..."
|
|
590
692
|
puts
|
|
591
693
|
|
|
592
694
|
pinned.each_with_index do |pr, idx|
|
|
593
695
|
pinned_manager.refresh_status(pr)
|
|
594
|
-
|
|
696
|
+
if compact
|
|
697
|
+
puts pinned_manager.display_pinned(pr, idx)
|
|
698
|
+
else
|
|
699
|
+
puts pinned_manager.display_detailed(pr, idx)
|
|
700
|
+
puts
|
|
701
|
+
end
|
|
595
702
|
end
|
|
596
703
|
|
|
597
704
|
pinned_manager.save_pinned(pinned)
|
|
598
|
-
puts
|
|
705
|
+
puts "---"
|
|
599
706
|
puts "Status updated at #{Time.now.strftime('%H:%M:%S')}"
|
|
600
707
|
end
|
|
601
708
|
|
data/lib/hiiro/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hiiro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.82
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Toyota
|
|
@@ -72,21 +72,14 @@ files:
|
|
|
72
72
|
- bin/h-buffer
|
|
73
73
|
- bin/h-commit
|
|
74
74
|
- bin/h-config
|
|
75
|
-
- bin/h-home
|
|
76
|
-
- bin/h-html
|
|
77
75
|
- bin/h-link
|
|
78
|
-
- bin/h-mic
|
|
79
|
-
- bin/h-note
|
|
80
76
|
- bin/h-pane
|
|
81
77
|
- bin/h-plugin
|
|
82
78
|
- bin/h-pr
|
|
83
79
|
- bin/h-project
|
|
84
|
-
- bin/h-remind
|
|
85
|
-
- bin/h-serve
|
|
86
80
|
- bin/h-session
|
|
87
81
|
- bin/h-sha
|
|
88
82
|
- bin/h-todo
|
|
89
|
-
- bin/h-video
|
|
90
83
|
- bin/h-window
|
|
91
84
|
- bin/h-wtree
|
|
92
85
|
- docs/README.md
|
data/bin/h-home
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require 'hiiro'
|
|
4
|
-
|
|
5
|
-
EDITOR = ENV.fetch('EDITOR', 'nvim')
|
|
6
|
-
BASE_DIR = Dir.home
|
|
7
|
-
|
|
8
|
-
o = Hiiro.init(*ARGV)
|
|
9
|
-
|
|
10
|
-
o.add_subcmd(:edit) { |*args|
|
|
11
|
-
system(EDITOR, __FILE__)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
o.add_subcmd(:path) { |*args|
|
|
15
|
-
print BASE_DIR
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
o.add_subcmd(:skf) { |*args|
|
|
19
|
-
Dir.chdir(BASE_DIR)
|
|
20
|
-
system('skf', *args)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
o.add_subcmd(:rg) { |*args|
|
|
24
|
-
Dir.chdir(BASE_DIR)
|
|
25
|
-
system('rg', '-S', *args)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
o.add_subcmd(:rgall) { |*args|
|
|
29
|
-
Dir.chdir(BASE_DIR)
|
|
30
|
-
system('rg', '-S', '--no-ignore-vcs', *args)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
o.add_subcmd(:ebin) { |*args|
|
|
34
|
-
Dir.chdir(File.join(Dir.home, 'bin'))
|
|
35
|
-
|
|
36
|
-
glob_patterns = []
|
|
37
|
-
globs = []
|
|
38
|
-
|
|
39
|
-
files = args.filter_map { |arg|
|
|
40
|
-
matches =
|
|
41
|
-
if arg.end_with?('*')
|
|
42
|
-
glob_patterns << arg
|
|
43
|
-
Dir.glob(arg)
|
|
44
|
-
elsif arg.is_a?(String)
|
|
45
|
-
glob_patterns << '*' + arg.to_s + '*'
|
|
46
|
-
Dir.glob('*' + arg.to_s + '*')
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
globs << matches
|
|
50
|
-
|
|
51
|
-
matches unless matches.empty?
|
|
52
|
-
}.flatten
|
|
53
|
-
|
|
54
|
-
system(EDITOR, *files.flatten)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if o.runnable?
|
|
58
|
-
o.run
|
|
59
|
-
else
|
|
60
|
-
puts :no_runnable_found
|
|
61
|
-
end
|
|
62
|
-
|
data/bin/h-html
DELETED
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
require "hiiro"
|
|
3
|
-
|
|
4
|
-
o = Hiiro.init(*ARGV)
|
|
5
|
-
o.add_subcmd(:vids) { |outfile, *args|
|
|
6
|
-
outfile = 'index.html' if outfile.nil?
|
|
7
|
-
|
|
8
|
-
hash = Digest::SHA1.hexdigest(Dir.pwd)
|
|
9
|
-
puts hash: hash
|
|
10
|
-
|
|
11
|
-
videos = Dir.glob('*.mp4').map { |vid|
|
|
12
|
-
next if File.directory?(vid)
|
|
13
|
-
|
|
14
|
-
vid.inspect
|
|
15
|
-
}.compact
|
|
16
|
-
|
|
17
|
-
puts video_count: videos.count
|
|
18
|
-
|
|
19
|
-
videos = videos.join(",\n")
|
|
20
|
-
|
|
21
|
-
template = <<~TEMPLATE
|
|
22
|
-
<html>
|
|
23
|
-
<head>
|
|
24
|
-
<style>
|
|
25
|
-
/* a, p, video {
|
|
26
|
-
margin-top: 20px;
|
|
27
|
-
} */
|
|
28
|
-
select, textarea {
|
|
29
|
-
margin-top: 20px;
|
|
30
|
-
width: 80%;
|
|
31
|
-
display: block;
|
|
32
|
-
}
|
|
33
|
-
.flex_links {
|
|
34
|
-
display: flex;
|
|
35
|
-
gap: 70px;
|
|
36
|
-
margin-top: 38px;
|
|
37
|
-
margin-bottom: 38px;
|
|
38
|
-
}
|
|
39
|
-
* {
|
|
40
|
-
font-size: 16pt;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
a {
|
|
44
|
-
font-size: 26pt;
|
|
45
|
-
}
|
|
46
|
-
</style>
|
|
47
|
-
<script type="text/javascript">
|
|
48
|
-
var favs = localStorage.getItem('favs-#{hash}') || '[]';
|
|
49
|
-
console.log({ favs: favs });
|
|
50
|
-
|
|
51
|
-
var videos = [
|
|
52
|
-
#{videos.gsub(/\n/, "\n ")}
|
|
53
|
-
];
|
|
54
|
-
|
|
55
|
-
function create_links() {
|
|
56
|
-
var container = document.getElementById('links');
|
|
57
|
-
var player = document.getElementById('player');
|
|
58
|
-
|
|
59
|
-
for(var x=0; x < videos.length; x++) {
|
|
60
|
-
var link = document.createElement('option');
|
|
61
|
-
link.value = x;
|
|
62
|
-
link.innerText = videos[x];
|
|
63
|
-
|
|
64
|
-
container.appendChild(link);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function load_video() {
|
|
69
|
-
var player = document.getElementById('player');
|
|
70
|
-
var src = document.getElementById('player_src');
|
|
71
|
-
var links = document.getElementById('links');
|
|
72
|
-
var idx = links.value;
|
|
73
|
-
var id = parseInt(idx);
|
|
74
|
-
src.src = videos[id];
|
|
75
|
-
player.load();
|
|
76
|
-
player.currentTime = 5;
|
|
77
|
-
player.play();
|
|
78
|
-
load_stats();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function save_video() {
|
|
82
|
-
var fav_videos = localStorage.getItem('favs-#{hash}') || '[]';
|
|
83
|
-
var json = JSON.parse(fav_videos);
|
|
84
|
-
console.log({ favs: fav_videos, json: json });
|
|
85
|
-
|
|
86
|
-
var vid = document.getElementById('links').value;
|
|
87
|
-
vid = videos[parseInt(vid)];
|
|
88
|
-
|
|
89
|
-
if(vid !== undefined) {
|
|
90
|
-
json.push(vid);
|
|
91
|
-
|
|
92
|
-
localStorage.setItem('favs-#{hash}', JSON.stringify(json));
|
|
93
|
-
fav_videos = localStorage.getItem('favs-#{hash}') || '[]';
|
|
94
|
-
json = JSON.parse(fav_videos);
|
|
95
|
-
console.log({ favs: fav_videos, json: json });
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
display_favs();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function rm_fav() {
|
|
102
|
-
var fav_videos = localStorage.getItem('favs-#{hash}') || '[]';
|
|
103
|
-
var json = JSON.parse(fav_videos);
|
|
104
|
-
console.log({ favs: fav_videos, json: json });
|
|
105
|
-
|
|
106
|
-
var sel = document.getElementById('favs_select');
|
|
107
|
-
var current_index = sel.selectedIndex;
|
|
108
|
-
vid = json[current_index];
|
|
109
|
-
|
|
110
|
-
json.splice(current_index, 1)
|
|
111
|
-
|
|
112
|
-
if(vid !== undefined) {
|
|
113
|
-
localStorage.setItem('favs-#{hash}', JSON.stringify(json));
|
|
114
|
-
fav_videos = localStorage.getItem('favs-#{hash}') || '[]';
|
|
115
|
-
json = JSON.parse(fav_videos);
|
|
116
|
-
console.log({ favs: fav_videos, json: json });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
display_favs();
|
|
120
|
-
|
|
121
|
-
if(sel.length == 0) return;
|
|
122
|
-
|
|
123
|
-
if(current_index >= sel.length) {
|
|
124
|
-
current_index = sel.length - 1;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
sel.selectedIndex = current_index;
|
|
128
|
-
load_fav();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function load_fav() {
|
|
132
|
-
var sel = document.getElementById('favs_select');
|
|
133
|
-
|
|
134
|
-
var player = document.getElementById('player');
|
|
135
|
-
var src = document.getElementById('player_src');
|
|
136
|
-
src.src = sel.value;
|
|
137
|
-
player.load();
|
|
138
|
-
player.currentTime = 5;
|
|
139
|
-
player.play();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function prev_fav() {
|
|
143
|
-
var sel = document.getElementById('favs_select');
|
|
144
|
-
if(sel.selectedIndex == 0) return;
|
|
145
|
-
sel.selectedIndex = sel.selectedIndex - 1;
|
|
146
|
-
load_fav();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function next_fav() {
|
|
150
|
-
var sel = document.getElementById('favs_select');
|
|
151
|
-
if(sel.selectedIndex >= sel.length - 1) return;
|
|
152
|
-
sel.selectedIndex = sel.selectedIndex + 1;
|
|
153
|
-
load_fav();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function export_favs() {
|
|
157
|
-
var text = document.getElementById('export_favs');
|
|
158
|
-
var data = localStorage.getItem('favs-#{hash}') || '[]';
|
|
159
|
-
var list = JSON.parse(data);
|
|
160
|
-
text.innerHTML = list.join("\\n");
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function display_favs() {
|
|
164
|
-
var sel = document.getElementById('favs_select');
|
|
165
|
-
sel.innerHTML = '';
|
|
166
|
-
|
|
167
|
-
var data = localStorage.getItem('favs-#{hash}') || '[]';
|
|
168
|
-
var favs = JSON.parse(data);
|
|
169
|
-
|
|
170
|
-
for(var x=0; x<favs.length; x++) {
|
|
171
|
-
var opt = document.createElement('option');
|
|
172
|
-
opt.value = favs[x];
|
|
173
|
-
opt.innerText = favs[x];
|
|
174
|
-
sel.appendChild(opt);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function clear_last() {
|
|
179
|
-
localStorage.removeItem('last_vid-#{hash}');
|
|
180
|
-
|
|
181
|
-
show_last();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function mark_last() {
|
|
185
|
-
var sel = document.getElementById('links');
|
|
186
|
-
var idx = sel.value;
|
|
187
|
-
var id = parseInt(idx);
|
|
188
|
-
|
|
189
|
-
localStorage.setItem('last_vid-#{hash}', videos[id]);
|
|
190
|
-
|
|
191
|
-
show_last();
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function show_last() {
|
|
195
|
-
var links = document.getElementById('links');
|
|
196
|
-
var div = document.getElementById('last_vid');
|
|
197
|
-
var last_vid = localStorage.getItem('last_vid-#{hash}') || 'no last vid';
|
|
198
|
-
div.innerHTML = last_vid;
|
|
199
|
-
var found = false;
|
|
200
|
-
if(last_vid != 'no last vid') {
|
|
201
|
-
for(var x=0; x<videos.length; x++) {
|
|
202
|
-
if(videos[x] == last_vid) {
|
|
203
|
-
found = true;
|
|
204
|
-
links.selectedIndex = x;
|
|
205
|
-
load_video();
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if(found == false) {
|
|
211
|
-
links.selectedIndex = 0;
|
|
212
|
-
load_stats();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function prev_vid() {
|
|
217
|
-
var sel = document.getElementById('links');
|
|
218
|
-
if(sel.selectedIndex == 0) return;
|
|
219
|
-
sel.selectedIndex = sel.selectedIndex - 1;
|
|
220
|
-
load_video();
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function next_vid() {
|
|
224
|
-
var sel = document.getElementById('links');
|
|
225
|
-
if(sel.selectedIndex >= sel.length - 1) return;
|
|
226
|
-
sel.selectedIndex = sel.selectedIndex + 1;
|
|
227
|
-
load_video();
|
|
228
|
-
mark_last();
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function load_stats() {
|
|
232
|
-
var sel = document.getElementById('links');
|
|
233
|
-
var cur = document.getElementById('current_idx');
|
|
234
|
-
var total = document.getElementById('total_links');
|
|
235
|
-
|
|
236
|
-
cur.innerHTML = sel.selectedIndex + 1;
|
|
237
|
-
total.innerHTML = sel.length;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function trash() {
|
|
241
|
-
var sel = document.getElementById('links');
|
|
242
|
-
var idx = sel.selectedIndex;
|
|
243
|
-
|
|
244
|
-
var container = document.getElementById('trash');
|
|
245
|
-
var link = document.createElement('option');
|
|
246
|
-
link.value = idx;
|
|
247
|
-
link.innerText = videos[idx];
|
|
248
|
-
|
|
249
|
-
container.appendChild(link);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function clear_trash() {
|
|
253
|
-
var container = document.getElementById('trash');
|
|
254
|
-
container.innerHTML = '';
|
|
255
|
-
}
|
|
256
|
-
</script>
|
|
257
|
-
</head>
|
|
258
|
-
<body>
|
|
259
|
-
:r!ls *.mp4 | sed 's@.*@<video height="480" controls><source src="&" type="video/mp4"></video>@'
|
|
260
|
-
<hr/>
|
|
261
|
-
|
|
262
|
-
<div id="last_vid">not loaded</div>
|
|
263
|
-
<div class="flex_links">
|
|
264
|
-
<a href="javascript:void(0);" onclick="mark_last()" />Mark Last</a>
|
|
265
|
-
<a href="javascript:void(0);" onclick="clear_last()" />Clear Last</a>
|
|
266
|
-
</div>
|
|
267
|
-
|
|
268
|
-
<div id="links_stats">
|
|
269
|
-
<span id="current_idx">0</span> /
|
|
270
|
-
<span id="total_links">99999</span>
|
|
271
|
-
</div>
|
|
272
|
-
|
|
273
|
-
<select id="links" size="5" onchange="load_stats(); load_video();">
|
|
274
|
-
</select>
|
|
275
|
-
|
|
276
|
-
<div class="flex_links">
|
|
277
|
-
<a href="javascript:void(0);" onclick="load_video()" />Load</a>
|
|
278
|
-
<a href="javascript:void(0);" onclick="save_video()" />Save</a>
|
|
279
|
-
<a href="javascript:void(0);" onclick="prev_vid()">Prev Vid</a>
|
|
280
|
-
<a href="javascript:void(0);" onclick="next_vid()">Next Vid</a>
|
|
281
|
-
</div>
|
|
282
|
-
|
|
283
|
-
<select id="favs_select" size="5" onchange="load_fav();">
|
|
284
|
-
</select>
|
|
285
|
-
|
|
286
|
-
<div class="flex_links">
|
|
287
|
-
<a href="javascript:void(0);" onclick="rm_fav()" />Remove Fav</a>
|
|
288
|
-
<a href="javascript:void(0);" onclick="load_fav()" />Load Fav</a>
|
|
289
|
-
<a href="javascript:void(0);" onclick="prev_fav()" />Prev Fav</a>
|
|
290
|
-
<a href="javascript:void(0);" onclick="next_fav()" />Next Fav</a>
|
|
291
|
-
</div>
|
|
292
|
-
|
|
293
|
-
<select id="trash" size="5">
|
|
294
|
-
</select>
|
|
295
|
-
|
|
296
|
-
<div class="flex_links">
|
|
297
|
-
<a href="javascript:void(0);" onclick="trash()" />Trash</a>
|
|
298
|
-
<a href="javascript:void(0);" onclick="clear_trash()" />Clear</a>
|
|
299
|
-
</div>
|
|
300
|
-
|
|
301
|
-
<textarea id="export_favs" rows="5" cols="40">
|
|
302
|
-
</textarea>
|
|
303
|
-
|
|
304
|
-
<div class="flex_links">
|
|
305
|
-
<a href="javascript:void(0);" onclick="localStorage.removeItem('favs-#{hash}'); display_favs();" />Clear Favs</a>
|
|
306
|
-
<a href="javascript:void(0);" onclick="export_favs()" />Export Favs</a>
|
|
307
|
-
</div>
|
|
308
|
-
|
|
309
|
-
<div id="player_wrapper">
|
|
310
|
-
<video id="player" height="480" controls>
|
|
311
|
-
<source id="player_src" src="">
|
|
312
|
-
</video>
|
|
313
|
-
</div>
|
|
314
|
-
|
|
315
|
-
<script type="text/javascript">
|
|
316
|
-
create_links();
|
|
317
|
-
display_favs();
|
|
318
|
-
show_last();
|
|
319
|
-
load_stats();
|
|
320
|
-
</script>
|
|
321
|
-
</body>
|
|
322
|
-
</html>
|
|
323
|
-
TEMPLATE
|
|
324
|
-
|
|
325
|
-
size = IO.write(outfile, template)
|
|
326
|
-
|
|
327
|
-
puts size: size
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
o.add_subcmd(:videos) { |outfile, *args|
|
|
331
|
-
puts :in_html_videos
|
|
332
|
-
|
|
333
|
-
if outfile&.match?(/^-/)
|
|
334
|
-
args = [outfile, *args]
|
|
335
|
-
outfile = nil
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
outfile = 'index.html' if outfile.nil?
|
|
339
|
-
|
|
340
|
-
if File.exist?(outfile) && args.none?{|a| a.match?(/-f/) }
|
|
341
|
-
puts 'File Exists: use -f flag to force'
|
|
342
|
-
else
|
|
343
|
-
tags = Dir.glob('**/*').map { |vid|
|
|
344
|
-
next if File.directory?(vid)
|
|
345
|
-
|
|
346
|
-
file_cmd = format('file --mime-type "%s"', vid)
|
|
347
|
-
result = %x[ #{file_cmd} ]
|
|
348
|
-
next unless result.match?(/video\//)
|
|
349
|
-
|
|
350
|
-
format('<p>%s</p><video height="480" controls><source src="%s"></video>', vid, vid)
|
|
351
|
-
}.compact
|
|
352
|
-
|
|
353
|
-
template = <<~TEMPLATE
|
|
354
|
-
<html>
|
|
355
|
-
<head>
|
|
356
|
-
<style>
|
|
357
|
-
a, p, video {
|
|
358
|
-
display: block;
|
|
359
|
-
margin-top: 20px;
|
|
360
|
-
}
|
|
361
|
-
</style>
|
|
362
|
-
</head>
|
|
363
|
-
<body>
|
|
364
|
-
:r!ls *.mp4 | sed 's@.*@<video height="480" controls><source src="&" type="video/mp4"></video>@'
|
|
365
|
-
<hr/>
|
|
366
|
-
%s
|
|
367
|
-
</body>
|
|
368
|
-
</html>
|
|
369
|
-
TEMPLATE
|
|
370
|
-
|
|
371
|
-
contents = format(template, tags.join("\n"))
|
|
372
|
-
bytes = IO.write(outfile, contents)
|
|
373
|
-
|
|
374
|
-
printf("video count: %d\n", tags.count)
|
|
375
|
-
printf("bytes_written: %d\n", bytes)
|
|
376
|
-
end
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
o.run
|
|
380
|
-
|