my_manga 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class Add < MyManga::CLI::Command
8
+ desc 'Add a manga to your library'
9
+ argument :url, required: true, desc: 'Manga url'
10
+
11
+ def call(url:)
12
+ manga = MyManga.add(url)
13
+
14
+ return unless manga
15
+
16
+ puts %("#{manga.name}" added to your library!)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './command'
4
+ require_relative './version'
5
+ require_relative './find'
6
+ require_relative './add'
7
+ require_relative './remove'
8
+ require_relative './list'
9
+ require_relative './download'
10
+ require_relative './update'
11
+ require_relative './mark'
12
+ require_relative './env'
13
+ require_relative './m_clean_up'
14
+
15
+ module MyManga
16
+ module CLI
17
+ # Registry for CLI commands
18
+ module Commands
19
+ extend Hanami::CLI::Registry
20
+
21
+ # see desc
22
+ class Version < MyManga::CLI::Command
23
+ desc 'Print version'
24
+
25
+ def call(*)
26
+ puts MyManga::VERSION
27
+ end
28
+ end
29
+
30
+ register 'version', Version, aliases: %w[v -v --version]
31
+ register 'find', Find, aliases: %w[search]
32
+ register 'add', Add
33
+ register 'remove', Remove, aliases: %w[delete]
34
+ register 'list', List, aliases: %w[library show]
35
+ register 'download', Download
36
+ register 'update', Update, aliases: %w[fetch]
37
+ register 'mark', Mark
38
+ register 'env', Env, aliases: %w[-e --environment]
39
+ register 'm:clean_up', MCleanUp, aliases: %w[purge]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ module MyManga
2
+ module CLI
3
+ # Base class for CLI commands
4
+ class Command < Hanami::CLI::Command
5
+ def manga_names(input)
6
+ all = MyManga.names
7
+ names = Array(input.to_s.split(',')).map(&:strip)
8
+
9
+ names.empty? ? all : all & names
10
+ end
11
+
12
+ def pad(string, width, with: ' ')
13
+ string.ljust(width + 2, with)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class Download < MyManga::CLI::Command
8
+ desc 'Download manga from your library'
9
+ argument :names, desc: 'Manga names (comma separated)'
10
+ option :all,
11
+ type: :boolean,
12
+ default: true,
13
+ desc: 'Download all unread'
14
+ option :list,
15
+ desc: 'List of chapters to download (comma separated)'
16
+ option :from,
17
+ desc: 'First chapter to download (must be used with TO)'
18
+ option :to,
19
+ desc: 'Last chapter to download (must be used with FROM)'
20
+
21
+ def call(names: nil, **options)
22
+ names = manga_names(names)
23
+ numbers = if options[:list]
24
+ options[:list].to_s.split(',').map(&:strip)
25
+ elsif options[:to]
26
+ (options.fetch(:from)..options.fetch(:to)).to_a
27
+ end
28
+
29
+ names.each do |name|
30
+ manga = MyManga[name]
31
+ chapters = numbers || manga.chapters_unread_numbers
32
+ count = chapters.length
33
+
34
+ next unless count.positive?
35
+
36
+ puts "Downloading #{count} Chapters from \"#{name}\""
37
+ MyManga.download(manga, chapters)
38
+ end
39
+
40
+ puts '...'
41
+ puts 'Finished Download!'
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class Env < MyManga::CLI::Command
8
+ desc 'Print the current environment'
9
+
10
+ def call(*)
11
+ puts MyManga.env
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class Find < MyManga::CLI::Command
8
+ desc 'Search for a manga by name'
9
+ argument :search_term, required: true, desc: 'Manga name'
10
+
11
+ def call(search_term:)
12
+ results = MyManga.find(search_term)
13
+
14
+ puts "Manga found for \"#{search_term}\""
15
+ puts '=' * (18 + search_term.length)
16
+
17
+ return if results.empty?
18
+
19
+ column_width = results.map { |r| r[:name].length }.max
20
+ puts pad('Name', column_width) + 'Url'
21
+ results.each do |result|
22
+ puts pad(result[:name], column_width) + result[:uri]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class List < MyManga::CLI::Command
8
+ desc 'View your manga list'
9
+ argument :names, desc: 'Manga names (comma separated)'
10
+
11
+ def call(names: nil)
12
+ names = manga_names(names)
13
+ names.one? ? list_detail(names.first) : list(names)
14
+ end
15
+
16
+ def list(names)
17
+ column_width = names.map(&:length).max || 10
18
+
19
+ puts 'Manga list'
20
+ puts '=========='
21
+ print pad('Name', column_width)
22
+ puts 'Chapters read/total (unread)'
23
+
24
+ names.sort.each do |name|
25
+ manga = MyManga[name]
26
+ read = manga.read_count
27
+ total = manga.total_count
28
+ unread = total - read
29
+
30
+ print pad(name, column_width)
31
+ puts "#{read}/#{total} (#{unread}) #{manga.uri}"
32
+ end
33
+ end
34
+
35
+ def list_detail(name)
36
+ manga = MyManga[name]
37
+ header = %(Manga details for "#{manga.name}")
38
+ chapters = manga.chapters_read
39
+ read = manga.read_count
40
+ total = manga.total_count
41
+ unread = total - read
42
+
43
+ puts header
44
+ puts '=' * header.length
45
+ print pad('Name', name.length)
46
+ puts 'Chapters read/total (unread)'
47
+ puts "#{name} #{read}/#{total} (#{unread}) #{manga.uri}"
48
+ puts
49
+ puts 'Chapters Read'
50
+ puts '-------------'
51
+ chapters[0..2].each do |chapter|
52
+ puts chapter.name
53
+ end
54
+ puts '...' if chapters.length > 4
55
+ puts chapters[-1].name if chapters.length > 3
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class MCleanUp < MyManga::CLI::Command
8
+ desc 'Remove the manga cache for M, the mangdown client'
9
+
10
+ def call(*)
11
+ return unless MyManga.mangdown_client_clean_up
12
+
13
+ puts 'M cache files removed'
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class Mark < MyManga::CLI::Command
8
+ desc 'Mark manga chapters as read/unread'
9
+ argument :flag, required: true, desc: '[read|unread]'
10
+ argument :names, desc: 'Manga names (comma separated)'
11
+ option :all,
12
+ type: :boolean,
13
+ default: true,
14
+ desc: 'Mark all'
15
+ option :list,
16
+ desc: 'List of chapters to mark (comma separated)'
17
+ option :from,
18
+ desc: 'First chapter to mark (must be used with TO)'
19
+ option :to,
20
+ desc: 'Last chapter to mark (must be used with FROM)'
21
+
22
+ def call(flag:, names: nil, **options)
23
+ names = manga_names(names)
24
+ if options[:list]
25
+ numbers = options[:list].to_s.split(',').map(&:strip)
26
+ output ||= numbers.join(', ')
27
+ elsif options[:to]
28
+ numbers = (options.fetch(:from)..options.fetch(:to)).to_a
29
+ output = [numbers.first, numbers.last].join('-')
30
+ end
31
+ output ||= '(all)'
32
+
33
+ names.each do |name|
34
+ manga = MyManga[name]
35
+ chapters = numbers || manga.chapters_numbers
36
+ count = chapters.length
37
+
38
+ next unless count.positive?
39
+
40
+ mark(manga, flag, chapters)
41
+ print %(Chapters #{output} from "#{name}" )
42
+ puts %(Marked as #{flag.capitalize})
43
+ end
44
+ end
45
+
46
+ def mark(manga, flag, chapters)
47
+ if flag == 'read'
48
+ MyManga.read!(manga, chapters)
49
+ else
50
+ MyManga.unread!(manga, chapters)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class Remove < MyManga::CLI::Command
8
+ desc 'Remove a manga from your library'
9
+ argument :name, required: true, desc: 'Manga name'
10
+
11
+ def call(name:)
12
+ return unless MyManga.remove(name)
13
+
14
+ puts %("#{name}" removed from your library!)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ module CLI
5
+ module Commands
6
+ # See desc
7
+ class Update < MyManga::CLI::Command
8
+ desc 'Update manga from your library'
9
+ argument :names, desc: 'Manga names (comma separated)'
10
+
11
+ def call(names: nil, **options)
12
+ names = manga_names(names)
13
+
14
+ puts 'Fetching Manga'
15
+ puts '...'
16
+
17
+ names.each do |name|
18
+ manga = MyManga[name]
19
+ old_total = manga.total_count
20
+ MyManga.update(manga)
21
+ new_total = MyManga[name].total_count
22
+ updated = new_total - old_total
23
+
24
+ next if updated.zero?
25
+
26
+ puts "Updated \"#{name}\": #{updated} new Chapters."
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyManga
4
+ VERSION = '1.1.6'
5
+ end
@@ -0,0 +1,28 @@
1
+ class Chapter < ActiveRecord::Base
2
+ belongs_to :manga
3
+
4
+ scope :read, Proc.new { where(read: true) }
5
+ scope :unread, Proc.new { where(read: false) }
6
+
7
+ def self.from_md(md_hash)
8
+ uri = md_hash.uri
9
+ name = md_hash.name
10
+ site = md_hash.site
11
+ number = md_hash.chapter
12
+
13
+ unless number
14
+ adapter = Mangdown.adapter!(uri, site, nil, name)
15
+ number = adapter.chapter[:chapter]
16
+ end
17
+
18
+ find_or_create_by(name: name, uri: uri, number: number)
19
+ end
20
+
21
+ def to_md
22
+ ::Mangdown::MDHash.new(name: name, uri: uri).to_chapter
23
+ end
24
+
25
+ def self.numbers
26
+ pluck(:number)
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ class Manga < ActiveRecord::Base
2
+ self.table_name = "manga"
3
+
4
+ has_many :chapters, dependent: :destroy
5
+
6
+ delegate :read, :unread, to: :chapters, prefix: true, allow_nil: false
7
+ delegate :numbers, to: :chapters_unread, prefix: true, allow_nil: false
8
+ delegate :numbers, to: :chapters, prefix: true, allow_nil: false
9
+
10
+ def self.from_md(md_manga)
11
+ manga = find_or_create_by(name: md_manga.name, uri: md_manga.uri)
12
+ manga.update_chapters(md_manga.chapters)
13
+ manga
14
+ end
15
+
16
+ def update_chapters(fetched_chapters)
17
+ fetched_chapters.each do |md|
18
+ chapter = Chapter.from_md(md)
19
+ chapter.manga = self
20
+ chapter.save
21
+ end
22
+ self.total_count = chapters.count
23
+ save!
24
+ end
25
+
26
+ def to_md
27
+ ::Mangdown::MDHash.new(name: name, uri: uri).to_manga
28
+ end
29
+
30
+ def chapters
31
+ super.order(:number)
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'test_helper'
2
+ require_relative '../../mangdown/lib/mangdown/client'
3
+ require_relative '../lib/mangdown/adapters/manga_here'
4
+ require 'timeout'
5
+
6
+ Mangdown.register_adapter(:manga_here, MangaHere)
7
+
8
+ class AdaptersTest < Minitest::Test
9
+ def setup
10
+ @manga_uri = 'http://www.mangahere.co/manga/bokutachi_wa_benkyou_ga_dekinai/'
11
+ end
12
+
13
+ def build_manga
14
+ Mangdown::MDHash.new(uri: @manga_uri).to_manga
15
+ end
16
+
17
+ def test_creates_manga
18
+ assert_silent do
19
+ build_manga
20
+ end
21
+ end
22
+
23
+ def test_chapter
24
+ manga = build_manga
25
+ chapter = nil
26
+
27
+ Timeout.timeout(10) do
28
+ chapter = manga.chapters[-1].to_chapter
29
+ end
30
+
31
+ assert chapter
32
+ end
33
+ end