im_reader 1.0.1 → 1.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f693637efa72f8b0c59dce1206e1e9716b3f5cac3335b2dac02bc1d6cc025548
4
- data.tar.gz: feac962d03b51b08322c7beb9258be0f39b6811f2e1f0f848f3e1ab996797fd0
3
+ metadata.gz: 3924b115a1d392eedfd385de5562d7315d0e944dbe24cfb9afe508fcf828c752
4
+ data.tar.gz: 662645729d3ad94fffd7657dbeaacd85cd23a9b8c73bf3eadc7eb6fce8c36713
5
5
  SHA512:
6
- metadata.gz: '038aacfbf6507b20e57ce5cf156d0ceb4a666b1eb0e555595d2d719744e64ad3ddb88ec83ca5b62bfbb19e56ba35af5be9f394fa8da102f794c06a39fc434a65'
7
- data.tar.gz: 746605c1a88fecbc0402082d58f5b54fcf93fced074182c20146da00d9d7aee7b8d756780b482c08592878e8350eece1566b2345fc02ddaf0f2c5871736e56b1
6
+ metadata.gz: 105c341e1024df66ecab60d327c18229c85e46e580e5b0c79a64b64a9725806b48f2f7a6dacb8a8a2bb23fab0b8cea9311c539c27dfe3e6880509d04eb086dfa
7
+ data.tar.gz: a3e49c2ea673decb70bd85a06a3da0df9e2c33e1e4d809c88bc5a89b0e3d73c56355ecdb1abe7a8c95f2aeb4a70e3af007081de0bc6a9c4d23c00cd50182ede3
data/README.md CHANGED
@@ -76,8 +76,11 @@ fr:
76
76
  buttons:
77
77
  start: "Commencer la lecture"
78
78
  messages:
79
+ invalid_url: "L'url de lecture est invalide."
80
+ missing_url: "L'url de lecture est manquante."
79
81
  loading: "Chargement du livre ..."
80
82
  reading_error: "Impossible de récupérer l’EPUB"
83
+ timeout_error: "Erreur de connexion : veuillez recharger la page."
81
84
  ```
82
85
 
83
86
  ---
@@ -87,7 +90,7 @@ fr:
87
90
  To work on the gem locally:
88
91
 
89
92
  ```bash
90
- git clone https://github.com/your-org/im_reader.git
93
+ git clone https://github.com/immateriel/im_reader.git
91
94
  cd im_reader
92
95
  bundle install
93
96
  ```
@@ -19,17 +19,43 @@
19
19
  $("#reader-root").append(overlay);
20
20
 
21
21
  var bookUrl = $root.data("book-url");
22
+ if (!bookUrl) {
23
+ $("#cover-content").html(`<p class="ui red text">${i18n.missing_url || "URL manquante."}</p>`);
24
+ return;
25
+ }
22
26
  var theme = "light";
23
27
  var fontSize = 100;
28
+ fetch(bookUrl, { method: "HEAD" })
29
+ .then((res) => {
30
+ if (!res.ok) {
31
+ // Si HEAD échoue, on tente GET pour récupérer le message texte
32
+ return fetch(bookUrl).then(async (resp) => {
33
+ const msg = await resp.text();
34
+ throw new Error(msg || i18n.reading_error || "Erreur de lecture.");
35
+ });
36
+ }
37
+ })
38
+ .then(() => startReader(bookUrl, i18n, overlay))
39
+ .catch((err) => {
40
+ console.error("[im_reader] load error:", err);
41
+ $("#cover-content").html(`<p class="ui red text">${err.message}</p>`);
42
+ });
43
+ }
24
44
 
45
+ function startReader(bookUrl, i18n, overlay) {
25
46
  var $viewer = $("#viewer"), $toc = $("#toc");
26
- var $prev_button = $("#prev_button"), $next_button = $("#next_button"), $btnTheme = $("#btnTheme");
47
+ var $prev_button = $("#prev_button"), $next_button = $("#next_button");
27
48
 
28
- if (!window.ePub) { console.error("ePub introuvable"); return; }
49
+ if (!window.ePub) {
50
+ $("#cover-content").html(`<p class="ui red text">ePub introuvable</p>`);
51
+ return;
52
+ }
29
53
 
30
- window.book = window.ePub(bookUrl, { openAs: "epub",
54
+ window.book = window.ePub(bookUrl, {
55
+ openAs: "epub",
31
56
  replacements: "blob",
32
- restore: false });
57
+ restore: false
58
+ });
33
59
 
34
60
  var rendition = book.renderTo("viewer", {
35
61
  width: "100%",
@@ -53,34 +79,17 @@
53
79
  if (iframe) iframe.setAttribute("sandbox", "allow-same-origin allow-scripts");
54
80
  });
55
81
 
56
- $prev_button.on("click", () => {
57
- rendition.prev();
58
- });
59
-
60
- $next_button.on("click", () => {
61
- rendition.next();
62
- });
63
-
64
- rendition.on("relocated", (location) => {
65
- if (book.locations.total > 0) {
66
- const current = book.locations.locationFromCfi(location.start.cfi);
67
- const total = book.locations.total;
68
- let percentage = current / total;
69
- if (location.atEnd) percentage = 1.0;
70
-
71
- $('#progressBar').progress('set percent', Math.round(percentage * 100));
72
- }
73
- });
82
+ $prev_button.on("click", () => rendition.prev());
83
+ $next_button.on("click", () => rendition.next());
74
84
 
75
85
  book.ready.then(() => Promise.all([book.loaded.navigation, book.loaded.manifest]))
76
86
  .then(([toc, manifest]) => {
77
-
78
87
  book.coverUrl().then((url) => {
79
88
  if (url) {
80
89
  $("#cover-content").html(`
81
- <img src="${url}" alt="${i18n.book_cover}">
82
- <button id="start_button" class="ui primary button">${i18n.start}</button>
83
- `);
90
+ <img src="${url}" alt="${i18n.book_cover}">
91
+ <button id="start_button" class="ui primary button">${i18n.start}</button>
92
+ `);
84
93
 
85
94
  overlay.on("click", "#start_button", () => {
86
95
  overlay.remove();
@@ -93,51 +102,24 @@
93
102
  });
94
103
 
95
104
  const $toc = $("#toc");
96
-
97
- function normalizeHref(href) {
98
- for (const key in manifest) {
99
- const entry = manifest[key];
100
- if (
101
- entry.href.endsWith(href) ||
102
- entry.href.endsWith("x" + href) ||
103
- entry.href.endsWith("/" + href)
104
- ) {
105
- return entry.href;
106
- }
107
- }
108
-
109
- // Par défaut
110
- return href;
111
- }
112
-
113
105
  toc.toc.forEach((chapter) => {
114
- const resolvedHref = normalizeHref(chapter.href);
115
-
116
106
  $("<a>")
117
107
  .addClass("item")
118
108
  .attr("href", "#")
119
109
  .text(chapter.label)
120
110
  .on("click", (e) => {
121
111
  e.preventDefault();
122
- rendition
123
- .display(resolvedHref)
124
- .catch((err) => {
125
- console.error("[im_reader] Display error:", err.message, resolvedHref);
126
- });
112
+ rendition.display(chapter.href).catch((err) => {
113
+ console.error("[im_reader] Display error:", err.message);
114
+ });
127
115
  })
128
116
  .appendTo($toc);
129
117
  });
130
118
  })
131
- .catch((err) => console.error("[im_reader] TOC load error:", err));
132
-
133
- book.ready.then(() => {
134
- return book.locations.generate(1000);
135
- }).then(() => {
136
- }).catch(e => console.error("Error, book not ready", e));
137
-
138
- rendition.on("displayError", (e)=> console.error("Error on display", e));
139
-
140
- rendition.display().catch(e=>console.error("Error while rendering book", e));
119
+ .catch((err) => {
120
+ console.error("[im_reader] TOC load error:", err);
121
+ $("#cover-content").html(`<p class="ui red text">${i18n.reading_error || "Erreur de lecture du livre."}</p>`);
122
+ });
141
123
  }
142
124
 
143
125
  $(function(){ var $root = $("#reader-root"); if ($root.length) initReader($root); });
@@ -8,12 +8,18 @@ module ImReader
8
8
  end
9
9
 
10
10
  def remote
11
- url = params[:url]
12
- uri = URI.parse(url)
13
- response = fetch_with_redirect(uri)
11
+ raw_url = params[:url].to_s.strip
12
+ return render plain: I18n.t('im_reader.messages.missing_url'), status: 400 if raw_url.empty?
13
+ uri = parse_uri(raw_url)
14
+ return render plain: I18n.t('im_reader.messages.invalid_url'), status: 400 unless uri
14
15
 
15
- if response.is_a?(Net::HTTPSuccess)
16
+ begin
17
+ response = fetch_with_redirect(uri)
18
+ rescue Net::OpenTimeout, Net::ReadTimeout
19
+ return render plain: I18n.t('im_reader.messages.timeout_error'), status: 504
20
+ end
16
21
 
22
+ if response.is_a?(Net::HTTPSuccess)
17
23
  send_data response.body,
18
24
  filename: File.basename(uri.path.presence || "remote.epub"),
19
25
  type: "application/epub+zip",
@@ -25,6 +31,24 @@ module ImReader
25
31
 
26
32
  private
27
33
 
34
+ def parse_uri(value)
35
+ raw = value.to_s.strip
36
+ return nil if raw.empty?
37
+
38
+ candidates = [raw, CGI.unescape(raw)].uniq
39
+
40
+ candidates.each do |c|
41
+ begin
42
+ uri = URI.parse(c)
43
+ return uri if uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
44
+ rescue URI::InvalidURIError, URI::InvalidComponentError
45
+ next
46
+ end
47
+ end
48
+
49
+ nil
50
+ end
51
+
28
52
  def fetch_with_redirect(uri, limit = 5)
29
53
  raise "Too many redirects" if limit == 0
30
54
 
@@ -3,6 +3,7 @@
3
3
  data-i18n='<%= {
4
4
  start: t("im_reader.buttons.start"),
5
5
  loading: t("im_reader.messages.loading"),
6
+ missing_url: t("im_reader.messages.missing_url"),
6
7
  book_cover: t("im_reader.elements.book_cover")
7
8
  }.to_json %>'>
8
9
  <aside class="ui vertical menu">
@@ -7,5 +7,8 @@ de:
7
7
  buttons:
8
8
  start: "Lesen beginnen"
9
9
  messages:
10
+ invalid_url: "Die URL zum Lesen ist ungültig."
11
+ missing_url: "Die Lese-URL fehlt."
10
12
  loading: "Buch wird geladen..."
11
13
  reading_error: "EPUB-Datei konnte nicht abgerufen werden"
14
+ timeout_error: "Verbindungsfehler: Bitte laden Sie die Seite neu."
@@ -7,5 +7,8 @@ en:
7
7
  buttons:
8
8
  start: "Start to Read"
9
9
  messages:
10
+ invalid_url: "The URL provide is invalid."
11
+ missing_url: "The reading URL is missing."
10
12
  loading: "Book is loading ..."
11
13
  reading_error: "Unable to retrieve the EPUB"
14
+ timeout_error: "Connection error: please reload the page."
@@ -7,5 +7,8 @@ es:
7
7
  buttons:
8
8
  start: "Comenzar la lectura"
9
9
  messages:
10
+ invalid_url: "La URL para leer no es válida."
11
+ missing_url: "Falta la URL de lectura."
10
12
  loading: "Cargando el libro..."
11
13
  reading_error: "No se pudo recuperar el EPUB"
14
+ timeout_error: "Error de conexión: por favor, recargue la página."
@@ -7,5 +7,8 @@ fr:
7
7
  buttons:
8
8
  start: "Commencer la lecture"
9
9
  messages:
10
+ invalid_url: "L'url de lecture est invalide."
11
+ missing_url: "L'url de lecture est manquante."
10
12
  loading: "Chargement du livre ..."
11
13
  reading_error: "Impossible de récupérer l’EPUB"
14
+ timeout_error: "Erreur de connexion : veuillez recharger la page."
@@ -7,5 +7,8 @@ pt:
7
7
  buttons:
8
8
  start: "Começar a leitura"
9
9
  messages:
10
+ invalid_url: "O URL para leitura é inválido."
11
+ missing_url: "O URL de leitura está em falta."
10
12
  loading: "Carregando o livro..."
11
13
  reading_error: "Não foi possível recuperar o EPUB."
14
+ timeout_error: "Erro de conexão: por favor, recarregue a página."
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ImReader
4
- VERSION = "1.0.1"
4
+ VERSION = "1.0.3"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: im_reader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elodie Ailleaume
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-30 00:00:00.000000000 Z
11
+ date: 2025-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sass