bandcamp-discover 0.7.0 → 0.7.2

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: 0e4dc43f9146747097ff3c34b9a581e02e96ad6e3dc812b84e7c77f1dd459147
4
- data.tar.gz: 208fdb4ae22424fb73d93722bbbb1158703a89c4626a4897dbfb79a5dffa32b1
3
+ metadata.gz: '094dffa15caad4bbabef29bd4b3d87789425e4736c2d06461d6917efc8fe600d'
4
+ data.tar.gz: de1a1d20425f1ecb984878b10541208849abbf7300cd46f80834e5197730ef1c
5
5
  SHA512:
6
- metadata.gz: 615dd28ade655b5c351249c4e98d1088102bb85d9ad002ca4e0396f49b60bd33c5fe058198f366dab1300f825e2e858a721e5ce715f866a77ce6a6f3afac8b32
7
- data.tar.gz: 6cc60964b92fd4cbc56544c13606397632fd526b4871cd1ae28feaa3cfcde54b1cbf7c6483c9c613e10e09a876a582d42f9d7890575cb0fb097fd5e351cdd3ed
6
+ metadata.gz: a6a057d4869da1039b00b9c2ffd5b4019123c4ee055cf392fd3fefc4b8fa7f427d2346081554e960a5416c95b52d507d9244912112dada5d0ddedec06820ac33
7
+ data.tar.gz: ae37374ebc23a193aedaed32cd741f01af048502cb9853596d6e9bf1438ec2040fcacdaee67f226951accf6bd9d674191faf8667f5bf86cc3b9216d84a408bbc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bandcamp-discover (0.7.0)
4
+ bandcamp-discover (0.7.2)
5
5
  async
6
6
  base64
7
7
  concurrent-ruby
@@ -3,6 +3,10 @@ require_relative "configuration"
3
3
 
4
4
  module BandcampDiscover
5
5
  class Analyzer
6
+ # The model replied, but not with the object asked for. Carries the reply so
7
+ # a failed job says what was said instead of where JSON.parse gave up.
8
+ class NoAnswer < StandardError; end
9
+
6
10
  # A per-call model still wins over the configured one so existing callers
7
11
  # keep their behaviour.
8
12
  def initialize(description, model = nil, credits: [])
@@ -17,10 +21,14 @@ module BandcampDiscover
17
21
  @description.to_s.match?(/label|platform|records/i)
18
22
  end
19
23
 
24
+ # The prompt says to default to false; a reply that never reached an answer
25
+ # is that default, not a reason to lose the whole scrape.
20
26
  def accepts_demos?
21
27
  return false unless llm?
22
28
 
23
29
  ask(BandcampDiscover.configuration.demos_prompt)
30
+ rescue NoAnswer
31
+ false
24
32
  end
25
33
 
26
34
  private
@@ -43,7 +51,15 @@ module BandcampDiscover
43
51
  extras: {response_format: {type: "json_object"}}
44
52
  )
45
53
 
46
- JSON.parse(response["choices"][0]["message"]["content"])["answer"]&.to_s&.downcase == "true"
54
+ answer(response["choices"][0]["message"]["content"])["answer"]&.to_s&.downcase == "true"
55
+ end
56
+
57
+ # response_format is advisory on OpenRouter: Anthropic models return the
58
+ # object inside a ```json fence, and some prepend a sentence.
59
+ def answer(content)
60
+ JSON.parse(content[/\{.*\}/m] || content)
61
+ rescue JSON::ParserError
62
+ raise NoAnswer, "model replied without a JSON object: #{content.to_s.strip[0, 200].inspect}"
47
63
  end
48
64
 
49
65
  # The bio alone cannot tell one person releasing under aliases from a
@@ -1,3 +1,3 @@
1
1
  module BandcampDiscover
2
- VERSION = "0.7.0"
2
+ VERSION = "0.7.2"
3
3
  end
@@ -23,12 +23,12 @@ module OpenRouter
23
23
 
24
24
  class Client
25
25
  class << self
26
- attr_accessor :requests, :answer
26
+ attr_accessor :requests, :answer, :raw
27
27
  end
28
28
 
29
29
  def complete(messages, model:, extras:)
30
30
  self.class.requests << {messages: messages, model: model, extras: extras}
31
- {"choices" => [{"message" => {"content" => JSON.generate("answer" => self.class.answer)}}]}
31
+ {"choices" => [{"message" => {"content" => self.class.raw || JSON.generate("answer" => self.class.answer)}}]}
32
32
  end
33
33
  end
34
34
  end
@@ -41,6 +41,7 @@ class AnalyzerTest < Minitest::Test
41
41
  OpenRouter.configuration.access_token = "token"
42
42
  OpenRouter::Client.requests = []
43
43
  OpenRouter::Client.answer = true
44
+ OpenRouter::Client.raw = nil
44
45
  end
45
46
 
46
47
  def teardown
@@ -99,6 +100,31 @@ class AnalyzerTest < Minitest::Test
99
100
  assert_equal "", OpenRouter::Client.requests.last[:messages].last[:content]
100
101
  end
101
102
 
103
+ def test_reads_the_answer_out_of_a_markdown_fence
104
+ OpenRouter::Client.raw = "```json\n{\"answer\": false}\n```"
105
+
106
+ refute Analyzer.new("bio").label?
107
+ end
108
+
109
+ def test_reads_the_answer_out_of_surrounding_prose
110
+ OpenRouter::Client.raw = "Sure. {\"answer\": true} Hope that helps."
111
+
112
+ assert Analyzer.new("bio").label?
113
+ end
114
+
115
+ def test_label_raises_a_named_error_carrying_a_reply_without_an_object
116
+ OpenRouter::Client.raw = "I don't see enough information to decide."
117
+
118
+ error = assert_raises(BandcampDiscover::Analyzer::NoAnswer) { Analyzer.new("bio").label? }
119
+ assert_includes error.message, "I don't see enough information"
120
+ end
121
+
122
+ def test_demos_defaults_to_false_on_a_reply_without_an_object
123
+ OpenRouter::Client.raw = "I don't see any mention of demos here."
124
+
125
+ refute Analyzer.new("bio").accepts_demos?
126
+ end
127
+
102
128
  def test_parses_the_answer
103
129
  OpenRouter::Client.answer = false
104
130
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bandcamp-discover
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian RUbisch
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-09-03 00:00:00.000000000 Z
10
+ date: 2026-09-04 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rake