APDM
A-Pressens Digitale Medier
Bucket for APDM specific stuff.
Usage intended for the pebble Pulp and the apps Lifeloop and Bandwagon, Strider, should it expand to include multiple papers, as well as any apps that come out of the Evergreen project.
Channels
channel = Channel.find('avisnavn')
channel.name
=> 'Avisnavn'
channel.domain
=> 'avisnavn.no'
channel.ad_tech
=> 123
# ... and loads of other handy methods
Design Elements
The api key is just an identifier, and is not used for authorization. In other words, you can make them up as you go along.
api = APDM::DesignElements.new('avisnavn', :api_key => 'bandwagon')
Header/Footer
Each newspaper has a standard header and footer along with the css necessary to display it. This header changes regularly. We cache these for a day by default.
api.header
api.
api.css
SiteStat
These are tracking scripts used for analytics. It is common to give each type of page within an application its own key.
api.site_stat('personalia.bursdag.hilsen.123456')
RSS Feeds
The newspapers each have an RSS feed:
channel = Channel.find 'avisnavn'
feed = APDM::Feed.new(channel)
feed.fetch
You can specify extra parameters for the number of entries it should return:
feed.fetch("amount" => 5)
Also, newspapers sometimes set up specific sections, like 'bandwagon', or 18368. These are specified as follows:
feed.fetch("sectionId" => 'bandwagon')
AdTech
AdTech ads are managed by Elisabeth Drange Tønnessen [email protected]. We receive a standardized .csv file with ad data, keyed off of a website id
. The website_id
in the .csv file corresponds to the ad_tech_id
in the Channels
list.
When APDM says that they just want to use the "default origo ads" this doesn't mean actual origo ads, it means the ads that we have stored with this gem.
It is important, if you create the snippets ahead of time, to make sure that all the ads on a single page are served with a uniq group id. We use a large rand: "grp=12345678990". This identifies them as having been shown together, simultaneously.
Sinatra extensions and workarounds for evil APDM proxy
If you are writing a Sinatra app that is going to live behind the evil apdm proxy, there's a Sinatra extension for you.
Enable it with:
require 'apdm/sinatra'
and adding this line to your Sinatra App class:
register Sinatra::APDM
Sinatra helpers
The following helper methods will be registered:
current_channel
Returns the current channel (based on current domain name - avisnavn.no if in development)design_elements
Returns the DesignElements instance for the current channel (see Design Elements above)ad_tech
Returns the AdTech instance for current channeldesign_elements_css_path
Returns the path (sinatra route) to where the css for current channel is published. Use in your templates to load css for channel, i.e.%link{ :href => design_elements_css_path, :rel => "stylesheet", :type => "text/css" }
ad_tech_api_js
Returns a JavaScript snippet that defines functionality (a globalwindow.api
object with several methods) needed by the ad_tech scripts. If you get a lot ofUncaught ReferenceError: api is not defined
you probably want to include the following in your template:
%script
= ad_tech_api_js
In order to make design elements or ad tech work properly, you need set a couple of configuration options:
set_design_elements_api_key
The api key for design elements (see above)set_ad_tech_context_prefix
The context_key/context_prefix of your application (i.e.bandwagon
)
Workarounds
You probably want to enable workarounds and cache headers proven to work with the evil apdm proxy (see the following example)
Example (all options enabled):
class MyApp < Sinatra::Base
register Sinatra::APDM
apdm_configure do
set_design_elements_api_key "kalender"
set_ad_tech_context_prefix "kalender"
enable_apdm_proxy_workarounds
enable_apdm_cache_headers
end
# (...)
Usage
For each page request, you can instantiate an ad_tech
ad repository for your current channel.
This needs to know what context (application, possibly which part of the application) the ads are being shown in.
ad_tech = AdTech.new(current_channel, :context_key => 'bandwagon') # e.g. 'bandwagon', or 'origo+profile'
ad_tech.slot(:toppbanner)
ad_tech.slot(:bunnbanner)
ad_tech.loader_scripts
It is possible to add local context in addition to the app context. For example, in Lifeloop, we specify personalia+<greeting-kind>
on the greeting category pages as well as individual greeting pages.
ad_tech = AdTech.new(current_channel, :context_key => 'personalia')
ad_tech.slot(:toppbanner, :local_context => 'mothersday')
=> 'personalia+mothersday'
Saxo
Origo/Apressen Web-to-Print module.
The local newspapers use Saxo to manage their images. This module writes metadata to jpg images for print, and transfers them to an FTP server, resulting in the images being pulled directly into the saxo system at the local papers.
Options
APDM::Saxo
needs to be initialized with a hash containing the server connection details.
For convenience, these live in the Channel objects.
channel = Channel.find 'avisnavn'
channel.saxo_config
=> { :server => 'ftp.example.com', :username => 'username', :password => 'password', :remote_dir => 'remote/dir' }
Metadata
The metadata is a hash with the following keys:
{
:keywords => 'some keywords',
:byline => 'the byline',
:headline => 'the headline',
:credit => 'the credits',
:source => 'the source',
:copyright => 'the copyright',
:caption => 'a caption'
}
Publication Dates (Issues)
Usually sometime before Christmas, someone realizes that we're running out of publication dates for some of the newspapers.
The dates of each issue are delivered to us in a variety of formats, typically an excel in an encoding which is not UTF-8, and with varying columns and date formats.
Til now, we have then massaged this in order to get a UTF-8 encoded .csv file that has the following fields:
YYYY-MM-DD;Issue Number;Acronym;NEWSPAPER NAME IN ALL CAPS
We don't use the issue number or acronym for anything. Also the acronyms are not unique.
Ideally we would just get the date and the domain name:
YYYY-MM-DD;avisnavn.no
To import this, replace the config/issues.csv
file with the newly massaged replacement,
and then run the command to import it:
./bin/apdm import_issues
Usage
The default behavior is to take the image located at ./localname.jpg
, write the metadata to it, and transfer it to the remote destination.
saxo = APDM::Saxo.new()
photo = saxo.write().to('localname.jpg', '/some/path')
saxo.transfer(photo)
If a :source
is provided, the image will be downloaded to /some/path/localname.jpg
before proceeding.
saxo = APDM::Saxo.new()
photo = saxo.write().to('localname.jpg', '/some/path', :source => 'http://www.example.com/remote.jpg')
saxo.transfer(photo)
saxo.transfer
returns true if it suceeded, otherwise false.
Acceptance Test
There is an acceptance test in /test
. This test by itself covers 98.99% of the saxo module in the project.
To run it
- copy
test/config-example.yml
totest/config.yml
- edit to taste
- run
rspec test